Navigation

Which component to use for moving between places, switching views, or narrowing what a list shows. Find the job, take the component, and read the “not when” before you commit: it names the thing people reach for by mistake, and what to use instead.

At a glance

JobUseNot whenInsteadBecause
Show where this page sits in a hierarchy, with a way back upBreadcrumbsYou need the list of places someone can goSidebarBreadcrumbs show the path here, not the other places.
The path is a sequence of steps in a processStepperA stepper shows position in a sequence; breadcrumbs show position in a hierarchy.
You are stepping through items of a set in placePagerChipThe pager chip says "4 of 19" and moves to the next one without leaving.
Let someone type to find and run any command or go anywhere, from anywhereCommandPaletteSomeone is choosing a value for a field by typingComboboxA combobox fills a field in a form; a palette runs a command and closes.
There are a few actions on one thingMenuA menu button opens beside its trigger and does not take the page over.
A frequent action wants one key of its own on one screen — J for next, E for doneShortcutsA single-key shortcut acts at once and has to be possible to turn off; the palette is a search opened by a chord.
The person is browsing places rather than searchingSidebarThe rail shows every place at once; a palette shows only what matches.
Let a narrow column of long names be read by scrolling, one at a timeDockThe list is the app's placesSidebarA rail of places has short names and marks the current page.
There is room for each row to show its name and a line of provenanceItemAn item list shows every row in full; a dock only grows the one in focus.
The column can simply be made wider by the readerSplitA resizable pane gives width persistently instead of momentarily.
Show an attribute of a row, and narrow the list to it when pressedFacetThe value is a status — done, failed, at riskTagA tag reports a state in a reserved tone; a facet is a neutral name and value.
The dimension is not on the rows, or the reader needs every value listedFilterA filter lists the values of a dimension in a menu above the list.
Narrow a list by one dimension, beside the other dimensionsFilterThe dimension is already printed on every rowFacetThe attribute on the row can be the control; there is no filter panel to go and find.
The choice is between two or three views of the same thingSegmentedViews are all present and equal; a filter removes rows.
The choice swaps the panel of contentTabsTabs swap panels; a filter narrows one list and can combine with others.
The person is entering a value on a form, not narrowing a listSelectA filter has an "any" state and acts at once; a form field holds a value until submit.
Open and close the navigation on a narrow screenHamburgerThe button opens a list of actions, not navigationMenuA menu button opens a menu of actions with its own keyboard contract.
The screen is wide enough to show the linksNavNavigation that fits should be visible, not behind a button.
Put the product's name and its top-level places across the top of every pageNavThere are more places than fit across the top, or they fall into groupsSidebarA rail holds a long, grouped list of places down the side.
The options swap panels inside one pageTabsTabs are panels in one place; nav items are places with their own URLs.
The reader needs to see where this page sits in a hierarchyBreadcrumbsBreadcrumbs show the path to here; the nav shows where you can go.
The header has to collapse on a phoneHamburgerThe hamburger is the button that opens the links in a drawer on a narrow screen.
Step through a set one item at a time without leaving the place you are inPagerChipJumping to any page of a long listPaginationPagination draws the page numbers; the chip only steps to the neighbour.
Under a table, saying which rows are on showTablePagerThe table pager carries the range and the pages for a table.
The person is moving through steps of a taskStepperA stepper says which steps are done; a pager chip has no notion of done.
Move between numbered pages of a long setPaginationPaging rows of a tableTablePagerThe table pager adds "Showing 26–50 of 61", renders nothing for one page, and is wired to usePagedTable.
Stepping through a set one item at a time without leaving a panePagerChip"4 of 19" with previous and next is one control; a page list is many.
Showing position in a sequence of steps the person is working throughStepperSteps have state — done, current, failed; pages do not.
Pick one of two or three views of the same thingSegmentedEach option shows a different panel of contentTabsA segmented control is a radiogroup, not a tablist; it changes how one thing is shown, not which thing.
The options narrow a list, or there may be more than three valuesFilterA filter is a dimension with a value; spelled out as a strip it grows across the page and hides which dimensions exist.
Each choice needs a description or a figure under itRadioCardsA radio card carries a title, a note and a figure, and the whole card is the hit target.
There are more than a handful of options to pick fromSelectA long run of segments stops reading as one control; a select holds the list behind one field.
List every place in an app down the side, grouped, with the current one markedSidebarThe options are panels of one pageTabsTabs swap panels in place; a sidebar moves between pages.
The items are a nested hierarchy the reader opens and closes — folders, a taxonomyTreeA tree has the keyboard contract for expand and collapse at any depth; the rail is one level of places.
The column is a long list of records or documents, not placesDockA dock lets every name be read at the focus point in a narrow column; a sidebar truncates them.
The column is a document's own headingsContentsContents tracks where you are in the document as you scroll.
Swap between panels of different content in one placeTabsThe options are views of the same content — a range, a grouping, list or gridSegmentedA segmented control is a radiogroup that changes how one thing is shown; a tablist promises a different panel per tab.
The options narrow a list by a dimension — status, owner, typeFilterA filter is a dimension with a value and sits beside other dimensions; tabs cannot combine.
The options are pages with their own URLs in an appSidebarPlaces are navigation and take aria-current="page"; tabs are panels inside one page.
The sections should be readable one after another, several open at onceAccordionAn accordion keeps every section in reading order; tabs hide all but one.
Browse a nested hierarchy, opening and closing branchesTreeThe hierarchy is the app's places, one level deepSidebarA rail of places is links with aria-current, not a tree.
The sections are content to read, opened and closed in placeAccordionAn accordion discloses content panels; a tree selects nodes in a hierarchy.
The structure is layers that cover one another — needs to tests, plan to milestonesLayeredGraphCoverage between layers is a graph, not a hierarchy.

Show where this page sits in a hierarchy, with a way back up.

Use when

  • A page several levels down — a work item inside a project inside a client — where going up a level is common.
  • The last crumb is the current page, rendered as text with aria-current="page"; separators are added for you.

Not when

  • You need the list of places someone can go → Sidebar. Breadcrumbs show the path here, not the other places.
  • The path is a sequence of steps in a process → Stepper. A stepper shows position in a sequence; breadcrumbs show position in a hierarchy.
  • You are stepping through items of a set in place → PagerChip. The pager chip says "4 of 19" and moves to the next one without leaving.

Confused with Sidebar, Stepper, PageHeadReact Breadcrumbs BreadcrumbClasses .breadcrumbs

See it on the demo page

CommandPalette

Let someone type to find and run any command or go anywhere, from anywhere.

Use when

  • An app with many places and actions, where a keyboard user wants ⌘K / Ctrl+K and a search (useCommandPalette binds it).
  • It takes the page over as a modal: focus stays in the search, arrows move the highlight, Enter runs.

Not when

  • Someone is choosing a value for a field by typing → Combobox. A combobox fills a field in a form; a palette runs a command and closes.
  • There are a few actions on one thing → Menu. A menu button opens beside its trigger and does not take the page over.
  • A frequent action wants one key of its own on one screen — J for next, E for done → Shortcuts. A single-key shortcut acts at once and has to be possible to turn off; the palette is a search opened by a chord.
  • The person is browsing places rather than searching → Sidebar. The rail shows every place at once; a palette shows only what matches.

Confused with Combobox, Menu, Dialog, Keys, ShortcutsReact CommandPaletteHooks useCommandPaletteClasses .command

See it on the demo page

Dock

Let a narrow column of long names be read by scrolling, one at a time.

Use when

  • A long list of records in a narrow column, where every name would otherwise be truncated: the one at the focus point grows to be legible.
  • Reading must not open anything — onSelect fires on a click and on Enter, never on scroll or focus.

Not when

  • The list is the app's places → Sidebar. A rail of places has short names and marks the current page.
  • There is room for each row to show its name and a line of provenance → Item. An item list shows every row in full; a dock only grows the one in focus.
  • The column can simply be made wider by the reader → Split. A resizable pane gives width persistently instead of momentarily.

Confused with Sidebar, Item, DocList, SplitReact DockClasses .dock

No demo page yet.

Facet

Show an attribute of a row, and narrow the list to it when pressed.

Use when

  • A row carries a recorded fact — "Owner · Dana", "Against · ISO 27001" — that a reader may want to filter by.
  • Showing an attribute plainly: without onClick it renders as a span, so a row does not change shape when the dimension becomes filterable.
  • A missing value: an empty one renders nothing; pass muted with the absence in words when you know why.

Not when

  • The value is a status — done, failed, at risk → Tag. A tag reports a state in a reserved tone; a facet is a neutral name and value.
  • The dimension is not on the rows, or the reader needs every value listed → Filter. A filter lists the values of a dimension in a menu above the list.

Confused with Tag, FilterReact Facet FacetsClasses .facet .facets

No demo page yet.

Filter

Narrow a list by one dimension, beside the other dimensions.

Use when

  • A table or list can be narrowed by Type, Status or Owner; put one Filter per dimension in a Filters row.
  • The trigger reads as the dimension until it holds a value, so a row of them says what can be narrowed.
  • Several values of one dimension at once ("gaps and conflicts") — pass multiple; values are OR-ed.

Not when

  • The dimension is already printed on every row → Facet. The attribute on the row can be the control; there is no filter panel to go and find.
  • The choice is between two or three views of the same thing → Segmented. Views are all present and equal; a filter removes rows.
  • The choice swaps the panel of content → Tabs. Tabs swap panels; a filter narrows one list and can combine with others.
  • The person is entering a value on a form, not narrowing a list → Select. A filter has an "any" state and acts at once; a form field holds a value until submit.

Confused with Facet, Segmented, Tabs, Menu, SelectReact Filter FiltersClasses .filter .filters

No demo page yet.

Hamburger

Open and close the navigation on a narrow screen.

Use when

  • The header's links do not fit on a phone; this button opens them, usually in a Drawer.
  • One button whose bars morph to an X, driven by open and announced through aria-expanded; label is required.

Not when

  • The button opens a list of actions, not navigation → Menu. A menu button opens a menu of actions with its own keyboard contract.
  • The screen is wide enough to show the links → Nav. Navigation that fits should be visible, not behind a button.

Confused with Drawer, Nav, MenuReact HamburgerClasses .hamburger

See it on the demo page

Put the product's name and its top-level places across the top of every page.

Use when

  • The header bar of an app or a site: the brand on the left, a few top-level places, account controls at the end.
  • The current place is marked with aria-current="page" (NavItem current), never a class.

Not when

  • There are more places than fit across the top, or they fall into groups → Sidebar. A rail holds a long, grouped list of places down the side.
  • The options swap panels inside one page → Tabs. Tabs are panels in one place; nav items are places with their own URLs.
  • The reader needs to see where this page sits in a hierarchy → Breadcrumbs. Breadcrumbs show the path to here; the nav shows where you can go.
  • The header has to collapse on a phone → Hamburger. The hamburger is the button that opens the links in a drawer on a narrow screen.

Confused with Sidebar, Tabs, Breadcrumbs, HamburgerReact Nav NavBrand NavLinks NavItemClasses .nav

See it on the demo page

PagerChip

Step through a set one item at a time without leaving the place you are in.

Use when

  • The head of a side pane that walks a set in order — sources, open findings, attachments: ‹ S4 of 19 ›.
  • In a Drawer header, so the way to the next item never scrolls away.

Not when

  • Jumping to any page of a long list → Pagination. Pagination draws the page numbers; the chip only steps to the neighbour.
  • Under a table, saying which rows are on show → TablePager. The table pager carries the range and the pages for a table.
  • The person is moving through steps of a task → Stepper. A stepper says which steps are done; a pager chip has no notion of done.

Confused with Pagination, TablePager, DrawerReact PagerChipClasses .pager-chip

See it on the demo page

Pagination

Move between numbered pages of a long set.

Use when

  • Search results, a gallery or a feed served a page at a time, where the page number is a place.
  • Building your own pager: PaginationItem takes aria-current="page"; PaginationGap is the elided run.

Not when

  • Paging rows of a table → TablePager. The table pager adds "Showing 26–50 of 61", renders nothing for one page, and is wired to usePagedTable.
  • Stepping through a set one item at a time without leaving a pane → PagerChip. "4 of 19" with previous and next is one control; a page list is many.
  • Showing position in a sequence of steps the person is working through → Stepper. Steps have state — done, current, failed; pages do not.

Confused with TablePager, PagerChip, StepperReact Pagination PaginationItem PaginationGapClasses .pagination

See it on the demo page

Segmented

Pick one of two or three views of the same thing.

Use when

  • Two or three mutually exclusive views of one set — Week / Month / Quarter, List / Grid.
  • Seeing the alternatives side by side is the point, and the strip is only as wide as the choices.
  • A short either/or answer in a form, named with label so the group reads as a question.

Not when

  • Each option shows a different panel of content → Tabs. A segmented control is a radiogroup, not a tablist; it changes how one thing is shown, not which thing.
  • The options narrow a list, or there may be more than three values → Filter. A filter is a dimension with a value; spelled out as a strip it grows across the page and hides which dimensions exist.
  • Each choice needs a description or a figure under it → RadioCards. A radio card carries a title, a note and a figure, and the whole card is the hit target.
  • There are more than a handful of options to pick from → Select. A long run of segments stops reading as one control; a select holds the list behind one field.

Confused with Tabs, Filter, RadioCards, ButtonGroupReact Segmented SegmentedItemClasses .segmented

See it on the demo page

List every place in an app down the side, grouped, with the current one marked.

Use when

  • An app with more places than fit in a header, in groups under mono headings (SidebarGroup).
  • Groups that come from data use SidebarSection, which can fold its items away when the rail is long.
  • A place that cannot hold anything yet stays a link, quieter, with why in its title — not disabled, not hidden.

Not when

  • The options are panels of one page → Tabs. Tabs swap panels in place; a sidebar moves between pages.
  • The items are a nested hierarchy the reader opens and closes — folders, a taxonomy → Tree. A tree has the keyboard contract for expand and collapse at any depth; the rail is one level of places.
  • The column is a long list of records or documents, not places → Dock. A dock lets every name be read at the focus point in a narrow column; a sidebar truncates them.
  • The column is a document's own headings → Contents. Contents tracks where you are in the document as you scroll.

Confused with Nav, Tabs, Tree, Dock, ContentsReact Sidebar SidebarGroup SidebarSection SidebarItem SidebarCountClasses .sidebar

See it on the demo page

Tabs

Swap between panels of different content in one place.

Use when

  • Each option shows a different panel — Overview, Activity, Settings — and only one is on screen at a time.
  • The panels are siblings of equal weight and the reader moves between them without leaving the page.

Not when

  • The options are views of the same content — a range, a grouping, list or grid → Segmented. A segmented control is a radiogroup that changes how one thing is shown; a tablist promises a different panel per tab.
  • The options narrow a list by a dimension — status, owner, type → Filter. A filter is a dimension with a value and sits beside other dimensions; tabs cannot combine.
  • The options are pages with their own URLs in an app → Sidebar. Places are navigation and take aria-current="page"; tabs are panels inside one page.
  • The sections should be readable one after another, several open at once → Accordion. An accordion keeps every section in reading order; tabs hide all but one.

Confused with Segmented, Filter, Accordion, SidebarReact Tabs TabClasses .tabs .tab

See it on the demo page

Tree

Browse a nested hierarchy, opening and closing branches.

Use when

  • Folders, a taxonomy, a nested set of requirements — any depth, with a count or size at the end of each row.
  • The whole tree is one Tab stop: Up/Down move through visible rows, Right expands then descends, Left collapses then rises.

Not when

  • The hierarchy is the app's places, one level deep → Sidebar. A rail of places is links with aria-current, not a tree.
  • The sections are content to read, opened and closed in place → Accordion. An accordion discloses content panels; a tree selects nodes in a hierarchy.
  • The structure is layers that cover one another — needs to tests, plan to milestones → LayeredGraph. Coverage between layers is a graph, not a hierarchy.

Confused with Sidebar, Accordion, DocListReact TreeClasses .tree

See it on the demo page

Other guides: Screens · Overlays · Status and feedback · Data · Input · Reading · Agents and live work

Generated from the when.ts beside each component — the same data the Claude Code plugin reads.