Components · Data

List & tree

A list is a set of things in an order. A tree is a set of things in a containment. Both are cheap to build and easy to make quietly dishonest — by hiding items, by ordering on something the clinician cannot see, or by collapsing a branch that holds the finding that matters.

Stable · v1.0 shadcn/ui WCAG 2.2 AA Merged: List · Tree

Overview

Use a list when items are peers and the reading is sequential: recordings for an encounter, results in a panel, prior notes. Use a tree only when containment is real and the clinician already thinks in it — a study containing series containing images, an order set containing orders. Never use a tree to compress a long flat list into something that fits.

If the items need comparing across the same attributes, neither is right — use Data grid, which gives you columns, sorting you can inspect, and a header row that stays put.

The order is stated

Every list says what it is ordered by, in words, above the first item. An unexplained order is read as importance.

The set is complete or says otherwise

A list shows everything it claims to show. Where it is filtered or truncated, that is stated in the list, not somewhere else.

Collapse hides depth, never state

A collapsed branch still reports what is inside it that would change a decision.

Anatomy

List with stated order and provenance
Recordings this encounter 4 of 4 · newest first
  • 12-lead ECG
    ST elevation V2–V4 · analysed, model v4.2
    15:41:02
  • hs-cTnI · repeat
    47 ng/L · ref < 34 ng/L · central lab
    15:41:00
  • 12-lead ECG
    No acute change · analysed, model v4.2
    14:26:38
  • hs-cTnI · baseline
    14 ng/L · ref < 34 ng/L · central lab
    14:41:00
PartRule
Order statement Required. "Newest first", "by priority then time". Present even when the order looks obvious.
Count 4 of 4, or 4 of 19 · filtered. The denominator is the unfiltered total, always.
Primary line What the item is. Full clinical name, never an internal code.
Secondary line Enough to act without opening the item — the value with its unit, the finding, the source. Optional but usually the reason the list is useful.
Timestamp Mono, tabular, absolute. Relative times ("2 h ago") never appear alone — see International design.
Current item aria-current plus fill and an inset rule. Never fill alone.

Order and completeness

The rule that carries the risk

A clinician scanning a list reads position as priority whether you intended it or not. So an order that is not stated is an implied clinical claim you did not mean to make. Every list in this system states its order in words and states the size of the set it is drawn from. A list showing 4 items out of 19 that says only "4 items" is misinformation, not brevity.

Tree

A tree is a list that admits it has depth. It earns its complexity only when the hierarchy is the clinician's own mental model; otherwise it costs two clicks to reach every leaf and hides the set size behind a triangle.

Containment the clinician already thinks in
  • Encounter · 13 Aug 2026
    • ECG  2
      • 15:41:02 · ST elevation V2–V4
      • 14:26:38 · no acute change

The collapsed Laboratory branch still reports that something inside it is critical. Collapse is allowed to cost you a click; it is not allowed to cost you a finding.

States

StateRendering
Loading Skeleton rows at the known count where the count is known; otherwise an activity indicator with the region named. Never an empty list that later fills.
Partial The items that loaded, plus an explicit row stating what did not and why. Never silently short.
Filtered Count reads n of N · filtered, with the filter tags above the list.
Empty The distinguishing sentence — none exist, none match, could not load.
Stale Last-updated time visible; the list never presents old data as current. See Interaction states.
Item unavailable The item still renders, with its state named. It does not disappear from the set — a row that vanishes changes the denominator without telling anyone.

Do's and don'ts

Do
Recordings 4 of 19 · filtered · newest first

Numerator, denominator, filter state and order. Four facts that stop the list from making a claim it cannot support.

Don't
Recordings 4 items

Fifteen recordings are hidden by a filter the clinician cannot see, in an order they cannot check.

Do
  • Laboratory  6  1 critical

Collapsed, but the branch still declares what is inside it that would change a decision.

Don't
  • Laboratory

A critical result one click away and no indication it is there. Collapse has hidden state, not depth.

Do
  • hs-cTnI · repeat
    47 ng/L · ref < 34 ng/L · central lab
    15:41:00

The secondary line makes the item actionable without opening it. Value, unit, reference, source, absolute time.

Don't
  • TNI2 result
    2 h ago

An internal code, no value, and a relative time that is wrong the moment the tab is left open.

Do
  • 12-lead ECG
    analysis unavailable · waveform viewable
    15:41:02

A degraded item stays in the set with its state named. The count still adds up.

Don't
  • hs-cTnI · baseline
    14:41:00

The ECG whose analysis failed has been dropped from the list entirely. Nothing on screen says a recording exists.

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/list.json
// orderedBy and total are required. A list cannot be rendered without
// declaring how it is sorted and how large the set really is.
<List
  label="Recordings this encounter"
  orderedBy="Newest first"
  total={19}
  items={visible}
  filtered
/>

if (items.length < total && !filtered && !onShowAll) {
  throw new Error("[List] a shortened list must be marked filtered or offer onShowAll.")
}

// A collapsed branch must be able to describe its contents, so summary
// is required on every node that has children.
type TreeNode = {
  id: string
  label: string
  children?: TreeNode[]
  summary?: { count: number; highest?: AlarmPriority }  // required if children
}
PropTypeNotes
labelstring Required. Names the set.
orderedBystring Required. Rendered verbatim; not derived from the sort key.
totalnumber Required. Unfiltered set size — the denominator.
filteredboolean Renders the filtered marker and the tag row.
maxDepth1 | 2 | 3 Tree only. Deeper structures must be flattened.
summaryNodeSummary Required on branches. Count plus highest contained priority.
NotJustAnyMed.Tech Design System · List & tree · v1.0 · draft for review
Reference applications named in this system are fictional; all patient data and reference ranges shown are fabricated and illustrative.