Components · Structure

Accordion & layout panel

Two containers with opposite promises. A layout panel says this is here, and it stays here. An accordion says this is here, but you will have to ask for it. In clinical software the second promise is expensive, so it is made rarely and never about anything that changes a decision.

Stable · v1.0 shadcn/ui WCAG 2.2 AA Merged: Accordion · Layout panel

Overview

Both exist to give a screen structure the clinician can rely on. The panel does it by drawing a boundary — everything inside belongs to one subject, and the panel header says which. The accordion does it by trading visibility for density.

That trade is the whole risk. Collapsed content is content nobody read. Not "content read later" — in practice, not read at all. So the question this page keeps asking is the same one: is it acceptable for a clinician to never open this? If the answer is no, it does not go in an accordion.

The boundary is the meaning

A panel's border is a claim about what belongs together. Nothing inside a patient panel belongs to another patient.

Collapsed means optional

Only content a clinician can safely never open is eligible for an accordion. Everything else is on screen.

The header carries the state

A closed section still reports what is inside it — the count, and any priority that would change what happens next.

Layout panel

Panel: a boundary with a stated subject
Serial troponin R. Halvorsen · MRN 55-1120
Baseline hs-cTnI
14ng/L
ref < 34 ng/L
drawn 14:41 · central lab
Repeat hs-cTnI · 1 h
47ng/L
+33 ng/L over 60 min · ref < 34 ng/L
drawn 15:41 · central lab
PartRule
Header Required. Names the content. On patient-scoped panels it also names the patient — see Patient header.
Subject One panel, one subject. A panel that mixes two patients' data has no valid header, and that is the signal it is wrong.
Border 1 px at ≥ 3:1 against both adjoining surfaces (WCAG 2.2 SC 1.4.11). The boundary is load-bearing, so it must actually be visible.
Body Scrolls internally only when the panel has a fixed height and its header stays put. Never a scroll region with no visible edge.
Toolbar Optional, inside the border — that is what makes its scope unambiguous. See Toolbar.
Elevation Panels sit flat. Elevation is reserved for things that overlay — see Elevation.

Accordion

Closed sections still report their contents

ST elevation 3.1 mm in V2–V4 measured at J+60 ms. Reciprocal depression in II, III, aVF.

AcuteLine model v4.2 · analysed 15:41:04 · decision support only

The third section is closed but declares that something advisory is inside it — a lead was reversed. A clinician who never opens it still knows to.

The rule that carries the risk

An accordion may never be the only route to an alarm, an active finding, an unacknowledged item, or anything the clinician must weigh before committing. Those are rendered expanded, or not in an accordion at all. If a section header would ever need to say "critical", the content behind it should not have been collapsed.

States

StateRendering
Collapsed Header, count, and highest contained priority. aria-expanded="false". The caret is decorative; the state is in the attribute.
Expanded Region labelled by its header button, so its boundary is announced.
Loading a section Content loads on expand; the header shows activity and the section keeps its height stable enough not to throw the page.
Section empty Expands to a stated reason, never to nothing. See Empty state.
Section unavailable Header stays, marked unavailable with a reason. Sections never disappear — a missing section is indistinguishable from a section that never existed.
Panel degraded The panel renders with its header and an explicit statement of what is missing. It does not collapse to nothing.

Do's and don'ts

Do

Closed, but the header declares what is inside. Collapse costs a click, not a finding.

Don't

A vague label hiding an advisory. Nothing on screen gives the clinician a reason to open it.

Do
ST elevation V2–V4 · unacknowledged

An active finding is rendered, not collapsed. Nothing that changes the next action lives behind a caret.

Don't

A critical alarm collapsed behind a count. The badge is red and still nobody opens it during a busy shift.

Do
Serial troponin R. Halvorsen · MRN 55-1120
14 → 47 ng/L over 60 min

One panel, one subject, named in the header. The boundary is a claim the header can back up.

Don't
Recent results
14 → 47 ng/L · 8 → 9 ng/L · 320 → 290 ng/L

Three patients' trajectories inside one border, under a header that names none of them.

Do

ST elevation 3.1 mm, V2–V4, at J+60 ms.

14:26:38 · 09:12:04 · 12 Aug 22:40:11

Two sections open at once. Comparing detail against priors is the reason both exist.

Don't

14:26:38 · 09:12:04 · 12 Aug 22:40:11

Exclusive-open. Opening the priors closed the analysis the clinician was reading, and they have to remember what it said.

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/accordion.json
$ npx shadcn@latest add https://md.notjustany.tech/r/layout-panel.json
// A collapsible section must be able to describe itself while closed,
// so summary is required — not optional metadata.
<Accordion multiple defaultOpen={["detail"]}>
  <Accordion.Section
    id="device"
    heading="Device & acquisition notes"
    headingLevel={3}
    summary={{ count: 2, highest: "advisory" }}
  >
    …
  </Accordion.Section>
</Accordion>

// Anything at advisory or above cannot be the sole occupant of a
// collapsed section — the component refuses to render it closed.
if (summary?.highest && PRIORITY_ORDER[summary.highest] >= PRIORITY_ORDER.advisory
    && summary.unacknowledged) {
  throw new Error("[Accordion] unacknowledged items at advisory+ cannot be collapsed.")
}

// A panel's header is required, and patient-scoped panels must name
// the subject they belong to.
<LayoutPanel heading="Serial troponin" subjectId="MRN-55-1120">…</LayoutPanel>
PropTypeNotes
multipleboolean Defaults to true. Exclusive-open must be opted into and is discouraged.
heading · headingLevelstring · 2|3|4 Required. Renders a real heading, not a styled div.
summarySectionSummary Required. Count plus highest contained priority; used in the closed header and the accessible name.
LayoutPanel headingstring Required. No unlabelled panels.
subjectIdstring Required on patient-scoped panels. Renders the subject in the header and guards against mixed-subject content.
NotJustAnyMed.Tech Design System · Accordion & layout panel · v1.0 · draft for review
Reference applications named in this system are fictional; all patient data and reference ranges shown are fabricated and illustrative.