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.
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
-
12-lead ECGST elevation V2–V4 · analysed, model v4.2
-
hs-cTnI · repeat47 ng/L · ref < 34 ng/L · central lab
-
12-lead ECGNo acute change · analysed, model v4.2
-
hs-cTnI · baseline14 ng/L · ref < 34 ng/L · central lab
| Part | Rule |
|---|---|
| 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
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.
- Never sort by relevance, confidence or model score without saying so and offering the underlying deterministic order. See Confidence & uncertainty.
- Never truncate silently. "Showing 10 of 34" with a control to see the rest, or show all 34. A list that stops at ten with no indication has hidden twenty-four things.
- Never reorder under the reader. New items arriving while the list is on screen are appended and marked, not slotted in — the same rule as Data grid.
- Empty is not blank. An empty list states which of "none exist", "none match the filter" and "could not load" applies — see Empty state.
- Filtered lists carry their filters visibly as removable tags — see Filter.
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.
-
Encounter · 13 Aug 2026
-
ECG 2
- 15:41:02 · ST elevation V2–V4
- 14:26:38 · no acute change
- Laboratory 6 1 critical
- Imaging 0 none ordered
-
ECG 2
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.
- Three levels maximum. Past that, the indentation stops being readable and the path stops being memorable. Flatten, or move to a breadcrumb plus a list.
- Branches report their contents — a count, and any state inside them at advisory priority or above.
- Expansion state is remembered per session, not reset on every navigation. Re-collapsing a branch the clinician opened is a small, repeated theft of attention.
- Never auto-collapse a branch the user opened when a sibling is expanded. Accordion behaviour in a tree loses work.
- A branch is never the only route to its leaves. Search reaches every leaf regardless of expansion state, and expands the path to what it finds.
States
| State | Rendering |
|---|---|
| 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
Numerator, denominator, filter state and order. Four facts that stop the list from making a claim it cannot support.
Fifteen recordings are hidden by a filter the clinician cannot see, in an order they cannot check.
- Laboratory 6 1 critical
Collapsed, but the branch still declares what is inside it that would change a decision.
- Laboratory
A critical result one click away and no indication it is there. Collapse has hidden state, not depth.
- hs-cTnI · repeat47 ng/L · ref < 34 ng/L · central lab
The secondary line makes the item actionable without opening it. Value, unit, reference, source, absolute time.
- TNI2 result
An internal code, no value, and a relative time that is wrong the moment the tab is left open.
- 12-lead ECGanalysis unavailable · waveform viewable
A degraded item stays in the set with its state named. The count still adds up.
- hs-cTnI · baseline
The ECG whose analysis failed has been dropped from the list entirely. Nothing on screen says a recording exists.
Accessibility
- A real
<ul>/<li>so the set size is announced. A stack of divs tells a screen-reader user nothing about how many items exist. - The order statement and count are inside the list's labelled region, so they are reachable in the same breath as the items rather than orphaned above it.
aria-currentfor the selected item, alongside fill and an inset rule. Three signals, one non-visual.- Trees use
role="tree",treeitemandgroup, witharia-expanded,aria-level,aria-setsizeandaria-posinset. - Tree keyboard model — one tab stop; arrows move and expand/collapse; Home/End reach first and last; type-ahead jumps by first letters.
- Branch state is in the accessible name — "Laboratory, 6 items, 1 critical, collapsed" — not only in a coloured chip.
- Rows are not link-in-link. A clickable row containing its own buttons is two overlapping targets; either the row navigates or the buttons act, never both in the same pixel.
- Targets ≥ 24 px including the tree's expand affordance, which is the one most often built at 12 (WCAG 2.2 SC 2.5.8).
- Reflow to 320 px — list items stack their secondary line, and tree indentation caps so deep levels do not push content off-screen (SC 1.4.10).
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.
- Effectiveness — the clinician knows the set is complete, or knows exactly how it is not. Nothing relevant is behind an unmarked collapse.
- Efficiency — the secondary line answers the question most items are opened to answer, so most items do not need opening.
- Satisfaction — an order that can be checked. Trust in a list is almost entirely trust in its ordering.
Clinical safety notes
Trace these in your risk file (ISO 14971) and usability engineering file (IEC 62366-1).
- Order stated in words. Mitigates: position read as clinical priority.
- Count shown as
n of N. Mitigates: a filtered subset read as the whole record. - No silent truncation. Mitigates: relevant items existing beyond an invisible cut-off.
- Collapsed branches report contained state. Mitigates: a critical result concealed by a closed node.
- Degraded items stay in the set with their state named. Mitigates: a recording believed not to exist because its analysis failed.
- No reordering under the reader. Mitigates: opening the wrong item because the row moved between look and click.
- Absolute timestamps. Mitigates: a relative time going stale on an unattended screen.
- Empty states distinguish none-exist from none-match from failed-to-load. Mitigates: a load failure read as an absence of findings.
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
}
| Prop | Type | Notes |
|---|---|---|
label | string |
Required. Names the set. |
orderedBy | string |
Required. Rendered verbatim; not derived from the sort key. |
total | number |
Required. Unfiltered set size — the denominator. |
filtered | boolean |
Renders the filtered marker and the tag row. |
maxDepth | 1 | 2 | 3 |
Tree only. Deeper structures must be flattened. |
summary | NodeSummary |
Required on branches. Count plus highest contained priority. |
Related
- Data grid — when items need comparing across attributes.
- Filter — how the filtered denominator is made visible.
- Empty state — the three kinds of nothing.
- Badge & pagination — counts on branches, and slicing long sets.
- Key–value pair — the secondary line's value, unit and reference.