Navigation
The persistent list down the left of an application: where staff are, and everywhere else they can go. Two types — Sectioned and Linear — and three widths.
The component is full height and sticky, because Figma draws it that way in every variant. The previews below take their height from the menu instead, so every destination is visible without scrolling a sidebar inside a page; that framing is the only thing this site changes about it.
Type: Sectioned — expanded
248px. Icon and label, with named groups a user would recognise (Patients, Clinical,
Nursing). Use Sectioned only when those labels do real work — do not invent groups to justify it.
A parent with children is a button with aria-expanded; a leaf is a link. Badges count
things to act on, and nothing else.
<nav class="sr-nav" aria-label="Primary">
<div class="sr-nav__header">…</div>
<div class="sr-nav__body">
<div class="sr-nav__section">
<span class="sr-nav__section-label">Patients</span>
<div class="sr-nav__list">
<button class="sr-nav__item" aria-label="Patient Search">…</button>
</div>
</div>
</div>
<div class="sr-nav__footer">…</div>
</nav>
<!-- Collapsed states -->
<nav class="sr-nav sr-nav--rail">…</nav> <!-- 108px, labels kept -->
<nav class="sr-nav sr-nav--collapsed">…</nav> <!-- 48px, icon only -->
Collapsed — rail
108px. Not a truncated expanded row: the icon moves above the label, both centre, and the label drops to caption (12px) so "Patient Search" fits without truncating. Section labels, badges and chevrons are dropped — the rail is for recognition, not detail.
Collapsed — icon only
48px. No persistent label; the label is revealed on hover and on focus-visible. Both, not just hover — a keyboard user can reach an item but can never trigger hover, so hover alone fails SC 1.4.13. Products need not adopt every width: Case Note Tracking ships expanded and rail only.
The persistent list down the left of an application: where staff are, and everywhere else they can go.
When to use
- As the primary navigation for any application with more than a handful of destinations.
- Choose the type by the shape of the destinations, not by how many there are:
- Sectioned, destinations fall into named groups a user would recognise (Patients, Clinical, Nursing). The labels do real work.
- Linear, a flat set with no meaningful grouping. Do not invent section labels to justify Sectioned.
When not to use
- Not for navigation inside a single record, use tabs or a section nav inside the page.
- Not on mobile at full height. Below 768px it must stop being a sticky 100vh rail; a full-height sidebar on a phone is the whole screen.
How it works
| State | Width | Behaviour |
|---|---|---|
| Expanded | 248px | Icon + label, section labels shown (Sectioned only) |
| Collapsed, rail | 108px | Icon above a permanently visible centred label, 12px |
| Collapsed, icon only | 48px | Icon alone; label revealed on hover and focus |
- The rail is not a truncated expanded row. Icon above label, both centred. Labels drop to 12px so the longest fits without truncating.
- Products need not adopt every state. Case Note Tracking (
125:5362) ships Expanded and rail only, and deliberately has no icon-only variant. - Sectioned packs items flush inside a group (the section labels separate them). Linear gives items a 16px gap, because nothing else does.
- The sidebar is full height and sticky, Figma draws it at full frame height in every variant, so that is component behaviour, not a layout choice for the consumer.
Do and don't
- Do mark the current destination with
aria-current="page", not a bespoke active class. - Do keep the collapse state where the user put it.
- Don't use a badge for anything that is not a count of things to act on.
- Don't put actions in the nav. It navigates; it does not do.
- Don't nest more than one level. If you need a third, the information architecture is wrong.
Accessibility
- Icon-only collapse must reveal its label on
:hoverAND:focus-visible. Hover alone fails WCAG 2.2 SC 1.4.13 and effectively SC 2.1.1, a keyboard user can tab to an item but can never trigger:hover. This is only about sighted keyboard users;aria-labelnames every item regardless. - Renders a real
<nav>with an accessible name. - Parents with children are
<button>witharia-expanded; leaves are links. - The collapse toggle says what it will do ("Expand navigation" / "Collapse navigation").
- Focus ring is the SR cyan ring, inset so it is never clipped by the rail edge.
Open questions
- Resolved 2026-08: the sidebar is 248px. It had shipped at 220px while derived its EPR content zones from 248px. Both moved together; 248px is also what the Figma item building block (
665:21099) is drawn at, and it is the width at which a row carrying both a badge and a chevron stops truncating.
Accessibility requirements
| Requirement | WCAG SC | How Single Record meets it | Test method |
|---|---|---|---|
| Navigation landmark with a name | 1.3.1 | A real nav element labelled "Primary", once per page — the sidebar, not the header, is the primary navigation when both are present. | Landmark review |
| Current destination is marked | 4.1.2 | aria-current="page" on the active item, not a bespoke active class, so it is announced and not only coloured. | Screen reader announce |
| Collapsed items keep their name | 4.1.2 | Every item carries aria-label whatever the width, so the icon-only rail is never a set of unlabelled buttons. | Screen reader, collapse first |
| Hidden labels reveal on focus, not only hover | 1.4.13 / 2.1.1 | The icon-only label appears on :hover AND :focus-visible. Hover alone is unreachable from the keyboard. | Keyboard tab through collapsed nav |
| Expandable parents announce their state | 4.1.2 | Parents are buttons with aria-expanded; the submenu is hidden, not merely off-screen. | Screen reader, expand and collapse |
| Collapse control says what it will do | 2.4.6 | "Expand navigation" / "Collapse navigation" — the outcome, not the glyph. | Screen reader announce |
| Focus visible | 2.4.7 | SR cyan ring, inset so the rail edge cannot clip it. | Keyboard tab at every width |