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.

7 of 7 patterns shown.
  • 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.