Guide
Choosing a navigation pattern
Six of the seven core navigation components compared here render as a row of labels, and they mean six unrelated things. Picking the wrong one costs the user more than a bug in the one you picked — and it is not fixable inside the component. This page is the choice, before you make it.
Start with the job, not the shape
The mistake almost always runs one way: a row of labels looks right, so the nearest component gets used. Ask what the labels are for instead. Each of the seven does exactly one of these jobs, and knowing which one rules out five of the other six.
The seven, and what each one claims
Choosing a pattern makes a claim about your content. If the claim is false, the component behaves correctly and the interface still misleads.
- Tabs Switch between views
Sibling views of one subject, in any order.
- What it renders
- Owns its panels and renders no links — tab buttons switch panels in place.
- State lives in
- The URL or local state — your choice, but say which.
- Back button should
- Your choice. Document it either way.
Used for a sequence.
Tabs advertise free movement, so a wizard in a tabset invites the user to skip step two and lose their place with no way to tell they have.
- Accordion Show and hide in place
Content revealed and hidden in place, without leaving the page.
- What it renders
- Owns its panels — each header is a button that shows or hides its own region.
- State lives in
- Local state, optionally the hash.
- Back button should
- Leave the page. Expanding is not navigation.
Used for sibling views.
Collapsed content is invisible to the browser’s own find-in-page. A reader searching for text that is right there concludes it does not exist.
- Stepper Move through a sequence
An ordered sequence with progress, and gates between the steps.
- What it renders
- Emits events — step buttons report requested moves, and you decide whether they happen.
- State lives in
- Workflow state, usually persisted so a refresh survives.
- Back button should
- Move one step back, not out of the flow.
Used for sibling views.
Gating and "complete" mean nothing when the parts are independent, so the component blocks movement it has no reason to block.
- Anchor Where am I in this page
Positions inside one long document.
- What it renders
- Renders real hash links, and emits the section the reader is currently in.
- State lives in
- Scroll position, plus the hash.
- Back button should
- Leave the page — not undo a scroll.
Used as navigation.
Pushing a history entry for every section the reader scrolls past fills the back stack, and back stops working as a way out of the page.
- Breadcrumb Go somewhere else
Where this page sits in a hierarchy.
- What it renders
- Renders real links — every crumb but the current one is an <a href> to its level.
- State lives in
- The route. Always.
- Back button should
- Leave the page.
Used for history.
A trail of visited pages is not a hierarchy. It changes under the user depending on how they arrived, so the same page reads differently twice.
- Mega Menu Go somewhere else
Global destinations, across the whole site.
- What it renders
- Renders real links to global destinations inside the panel it opens.
- State lives in
- The route. Always.
- Back button should
- Leave the page.
Used as a sitemap.
Sixty links in one panel is a directory, and nobody browses a directory. Past roughly thirty, search beats structure.
- Pagination Which page of results
Which slice of a result set is on screen.
- What it renders
- Emits events — page buttons emit the new page number; the data and the URL stay yours.
- State lives in
- The URL — it is the most obviously shareable state here.
- Back button should
- Return to the previous page of results.
Used over unstable data.
Page numbers need a stable total and a stable order. On data that changes between requests, rows move across pages and the reader misses one or sees it twice.
Navigation state is addressable state
An active tab, an expanded path, a current page, a wizard step and a selected anchor all want the same five things: back and forward, refresh, sharing, server rendering, and analytics. A controlled input gives you none of them — controlled state alone is not a routing contract.
Which is why the "state lives in" column above is a question you have to answer, not a default the kit picks for you. The components stay deliberately unopinionated about routing, so they stay usable in a hybrid or non-routed app — and that means the addressability is yours to wire.
Why these all work with the keyboard
Because none of it was implemented. Every one of these components is built from a real <a href> or a real <button>, so Tab, Enter, Space, middle-click, "open in new tab" and the browser's own focus ring arrive for free and cannot drift apart from each other. A div with a click handler looks identical and has none of them.
It is a rule rather than a habit here: a build gate fails if a navigation component reaches for a div, or gives a real control an ARIA role that throws its own semantics away. If you extend one of these, the same rule is what keeps the extension as accessible as the original.
On a narrow screen
A horizontal row of labels does not fit 360px. Six of the seven need a second presentation, and they do not all need the same one — swapping a pattern for a different pattern would change what it means.
- Tabs
- A compact select: Jump Menu.
- Anchor
- A collapsed rail, then the same select: Jump Menu.
- Breadcrumb
- Back-plus-title, because a breadcrumb knows the "up" target: Back / Up.
- Stepper
- "Step 3 of 7", with the current step’s label.
- Pagination
- Previous and next with a summary; no number window.
- Mega Menu
- A drawer. It is the one family incomplete without a second pattern.
- Accordion
- Nothing — it is already vertical.
Next
Pick the row that matches your job and open its component page for the API. If two rows both look right, the content is ambiguous rather than the guidance — and that is worth resolving before you write the markup, because no component choice will make it unambiguous later.