Sidebar & Rail
Also called side nav, nav rail, app navigation, left nav
A persistent vertical navigation region beside the main content, optionally collapsed to icons.
Example
Analytics
The sidebar stays put while this changes. That permanence is the whole point — the current place is answered without opening anything.
Accessible names in expanded mode
Overview · Analytics · Documents · Team · Settings
Identical in both modes. Collapsing changes what is painted, not what is announced — and the current destination carries aria-current="page" rather than only a background colour.
When to use it
- The app has a stable set of top-level places people move between all day.
- The current location needs to stay visible while working — a dashboard, an editor, an admin panel.
- There is horizontal room to spare, or the layout can afford a rail when there is not.
When not to
- There are three destinations. A horizontal nav in the header costs nothing and reads faster.
- The content needs the full width — a document editor, a canvas, a data table with twenty columns.
- The destinations are marketing pages with deep sub-structure. That is a header nav, possibly a mega menu.
Trade-offs
- Always visible, so the current place and the available places are answered without interaction.
- Scales down to a rail instead of disappearing entirely, unlike a header nav.
- Vertical lists take more items comfortably than a horizontal row does.
- Costs 200–280px of width permanently, which is a lot on a laptop.
- The rail hides labels, and icon-only navigation is guessy for anything beyond the obvious five.
- Grows badly: teams keep adding items until it needs sections, and then it needs a scrollbar.
Accessibility
What this pattern needs in order to work for everyone.
- Keyboard
- Plain links in a list. Tab moves through them; do not intercept the arrow keys unless you have built a full menubar, which a sidebar is not.
- Collapsing must not change the tab order or drop items — the rail has exactly the same destinations as the expanded state.
- Give it a skip link if it is long. Tabbing past fifteen nav items to reach the content is a daily tax.
- Roles and state
- Wrap it in `<nav>` with a label. If there are two navs on the page, both need distinct labels — “Main” and “Account”, not two anonymous regions.
- Mark the current destination with `aria-current="page"`. Highlighting it with background colour alone says nothing to a screen reader.
- In rail mode the label is still required: keep the text and hide it visually with a screen-reader-only class, or the link's accessible name becomes the icon's file name — or nothing at all.
- The collapse toggle is a button with `aria-expanded` and a name that says what it does — “Collapse sidebar”, not a bare chevron.
- Focus
- Collapsing or expanding keeps focus on the toggle. On mobile, where the sidebar becomes a drawer, it is a dialog: focus goes in, is trapped, Escape closes, and focus returns to the opener.
In the wild
- Linear — Persistent sidebar with sections, collapsing to a rail that keeps every destination reachable.
- VS Code activity bar — A rail by default, with labels in tooltips and the full names kept in the accessibility tree.
Compared with
Side-by-side breakdowns of patterns that solve a similar problem.