Components · Data

Badge & pagination

Both components exist because a set is bigger than the screen. A badge says how many there are; pagination says which ones you are looking at. Both are answers to the same clinical question — what am I not seeing? — and both are dangerous when they answer it approximately.

Stable · v1.0 shadcn/ui WCAG 2.2 AA Merged: Badge · Pagination

Overview

A badge is a count and nothing else. It never carries clinical state, never replaces a Status chip, and never becomes an alarm by turning red. A count of three tells you there are three things; it does not tell you any of them is critical, and it must not pretend to.

Pagination is the more consequential of the two, because it hides things. Its rule follows directly from Filter: a clinician must always be able to see the size of the whole set and know that something outside the current page needs attention.

Counts are exact

No "99+", no rounding, no approximation. A number a clinician cannot trust is worse than no number.

A count is not a state

Badges never take an IEC alarm hue. Quantity and priority are separate facts and get separate components.

The whole set is knowable

Pagination always shows the total, and always reports anything urgent on a page you are not on.

Badge

Counts, and what sits next to them
  • Laboratory 6 1 critical
    Count and priority as two separate statements
  • Prior recordings 3
    A plain count, carrying no clinical claim
  • Imaging 0
    Zero is rendered, not hidden — "none ordered" is information
The rule that carries the risk

A badge never uses an --alarm-* colour to mean "some of these are serious". A red badge is an alarm signal borrowed for a quantity, and it does two kinds of damage: it dilutes the IEC 60601-1-8 palette everywhere else in the product, and it lets a critical finding be represented by a number nobody has to open. Where priority exists, say it in words with a status chip beside the count.

The single exception is documented on Colour and applies only to the alarm banner's own occurrence counter, where the surrounding component already carries the priority.

Pagination

Prefer not to paginate at all. Virtual scrolling with a fixed header keeps the set continuous and the total visible, and it does not create the class of error where a patient exists on page three. Paginate when the set is genuinely large, the order is stable, and a page boundary carries no clinical meaning.

Position, total, and what is elsewhere
2 unacknowledged urgent results on page 3
PartRule
Range and total Required. 1–25 of 63. Never "Page 1 of 3" alone — the clinician needs the set size, not the page count.
Order statement Required. Page boundaries are meaningless without a stated order, and a changing order moves items between pages.
Current page aria-current="page" plus fill and weight. Never fill alone.
Off-page alarms Anything unacknowledged at advisory priority or above on another page is reported above the set, with a route to it.
Page size Fixed per view and remembered per session. It never changes as a side effect of sorting or filtering.
Where pagination is prohibited

Never paginate an alarm queue, an acknowledgement list, a handover view, or any set a clinician is expected to work to zero. In those views every item must be reachable by scrolling, because a page boundary is an invitation to stop. See Triage worklist and Acknowledge & escalate.

States

StateRendering
Single page Controls hidden; the range line still renders — 1–19 of 19.
Loading a page The previous page stays on screen with activity shown. Pagination never blanks the region, and the control keeps its width so the layout does not jump.
Total unknown 1–25 of at least 25 with the reason. Never a fabricated total and never a bare page number.
Set changed underneath Position is re-anchored to the item the clinician was on, and the change is stated. Never silently the same page index over different content.
Count unloaded (badge) with an accessible reason, never 0.
Count updating (badge) Updates on data arrival without animation, and never reorders what it sits on.

Do's and don'ts

Do
Laboratory 6 1 critical

Quantity and priority stated separately. Six results; one of them is critical; both facts survive greyscale.

Don't
Laboratory 6

A red count. It borrows the IEC critical hue to mean "some of these matter", and dilutes it everywhere the product uses it properly.

Do
Imaging 0 none ordered
Pathology count unavailable

Measured zero and unknown are different renderings. One is a fact; the other is a gap.

Don't
Imaging
Pathology 0

A hidden zero and a failed count rendered as zero. The clinician reads "nothing to see" twice, and is wrong once.

Do
1–25 of 63 · ordered newest first

Range, total and order. The clinician knows exactly how much of the record is off-screen and why it is off-screen.

Don't
Page 1 of 3

A page count instead of a set size. Three pages of what — thirty results or three hundred?

Do
2 unacknowledged urgent results on page 3

A page boundary is a display convenience, not a boundary on what the clinician is told.

Don't

Two urgent results sit on page 3 and nothing on page 1 says so. Most clinicians never reach page 2.

Do
1–19 of 19 · ordered newest first

One page, controls hidden, range line still present. "You are seeing everything" is worth saying out loud.

Don't
Showing 99+ results

A capped count. The difference between 100 and 900 is the difference between a manageable list and an unworkable one.

Accessibility

Outcomes of use

What this contributes to, in the terms of Usability & context of use. These are attributes believed to contribute to an outcome; the outcome itself is settled by observing real use in a specified context, not by this page.

Clinical safety notes

Risk controls carried by this component

Trace these in your risk file (ISO 14971) and usability engineering file (IEC 62366-1).

Implementation

$ npx shadcn@latest add https://md.notjustany.tech/r/badge.json
$ npx shadcn@latest add https://md.notjustany.tech/r/pagination.json
// A badge takes a count and the thing being counted. There is no
// variant prop, because a badge has no clinical variants.
<Badge count={6} of="results" />
<Badge count={null} of="results" unavailableReason="Lab feed unreachable" />

// Enforced at the boundary: no alarm token may reach a badge.
if (props.className && /alarm-(critical|urgent|advisory)/.test(props.className)) {
  throw new Error("[Badge] alarm colours are reserved. Use StatusChip for priority.")
}

// Pagination requires the set size and the order, and computes what is
// unacknowledged outside the current page.
<Pagination
  page={1}
  pageSize={25}
  total={63}
  orderedBy="Newest first"
  offPage={{ urgent: 2, page: 3 }}
  prohibitedFor={["alarmQueue", "handover"]}   // dev-time guard
/>
PropTypeNotes
countnumber | null Required. null renders , never 0.
ofstring Required. What is counted; goes into the accessible name.
unavailableReasonstring Required when count is null.
totalnumber | "atLeast" Required. Never fabricated; unknown totals render as "at least n".
orderedBystring Required. Rendered verbatim beside the range.
offPageOffPageSummary Unacknowledged items at advisory priority or above, elsewhere in the set.
NotJustAnyMed.Tech Design System · Badge & pagination · v1.0 · draft for review
Reference applications named in this system are fictional; all patient data and reference ranges shown are fabricated and illustrative.