Designer view

Sidebar Nav

A persistent navigation region pinned to a viewport edge — typically the inline-start (visual left in LTR) on desktop, collapsing to a drawer on mobile. Holds links to independent pages or top-level sections of an application. Distinct from Tabs (in-page content switching), MenuButton (transient action surface), and Drawer-as-navigation (the modal on-demand variant of this pattern). SidebarNav is the canonical pattern for multi-section apps with persistent global navigation.

When to use

Use

For persistent global navigation in multi-section apps — dashboards, admin panels, content management systems, documentation sites with multi-page topics. The user sees all top-level destinations at all times (or reveals them via the collapsible toggle), navigates between them via clicks/Enter, and the URL changes on activation.

Avoid

For in-page content switching — that is `Tabs`. For transient action menus — that is `MenuButton`. For contextual disclosure of secondary content — that is `Disclosure` or `Accordion`. For mobile-only navigation — combine with `Drawer[variant=navigation]` for the collapsible-on-narrow-viewports pattern.

Versus related

  • tabs

    `SidebarNav` navigates between independent pages (URLs change, content reloads); `Tabs` switches between content panels in the same page (URL stays the same in canonical implementations). The semantic distinction drives the role and the DOM: sidebar uses `<nav>` with anchor links; tabs use `tablist` with buttons.

  • drawer

    `Drawer[variant=navigation]` is the temporary modal-on-mobile counterpart of SidebarNav. They compose: persistent SidebarNav on desktop, Drawer for the same nav on mobile (collapses below `breakpoint.md`). The drawer-variant is invoked by a trigger (hamburger MenuButton).

  • menu-button

    `MenuButton` is a transient action surface invoked on demand; `SidebarNav` is a persistent navigation region always visible (or collapsibly visible). The role differentiates: `role="menu"` for MenuButton, `<nav>` for SidebarNav. Sidebar styled as menu-button is a common antipattern.

  • accordion

    `Accordion` discloses content within a single page; `SidebarNav` navigates between independent pages. Sidebars may contain accordion-style collapsible groups for nested navigation, but the leaf items are still anchor links — the accordion is structural within the sidebar, not the sidebar itself.

Highlight
Fig 1.1 · Sidebar Nav · Designer view
Designer

Figma anatomy

Slot Figma type Hint
root frame Full-block-size auto-layout vertical frame; pinned to inline-start of viewport
group frame Vertical frame with optional label heading and items inside
group-label text Heading text style; uppercase or small-caps for category dividers
item instance Nav item component instance with active and inactive variants
item-icon instance Icon component instance per item; required in collapsed variant
item-label text Item text style; visibility property bound to expanded state
badge instance Badge component instance; visibility bound to "has notification" state
footer frame Auto-layout vertical frame pinned to bottom of sidebar
Designer

Token usage per slot

root
spacing
  • paddingspacing.compact
  • gapspacing.tight
color
  • backgroundcolor.surface.sunken
  • bordercolor.border.subtle
group
spacing
  • gapspacing.tight
group-label
color
  • foregroundcolor.text.muted
typography
  • sizetext.xs
  • weightweight.medium
  • trackingtracking.wide
item
spacing
  • paddingspacing.compact
  • gapspacing.compact
radius
  • cornerradius.sm
color
  • foregroundcolor.text.primary
  • ringcolor.border.focus
typography
  • sizetext.sm
item-icon
color
  • foregroundcolor.text.muted
item-label
color
  • foregroundcolor.text.primary
typography
  • sizetext.sm
badge
spacing
  • paddingspacing.tight
radius
  • cornerradius.pill
color
  • backgroundcolor.accent.bg
  • foregroundcolor.accent.fg
typography
  • sizetext.xs
  • weightweight.semibold
footer
spacing
  • paddingspacing.compact
  • gapspacing.tight
Both

Figma ↔ Code property map

FigmaTypeCodeNotes
VariantVariantvariantMaps expanded / collapsed.
CollapsibleBooleancollapsibleToggles the user-facing collapse affordance (typically a chevron-button at the sidebar's inline-end edge).
DensityVariantdensitycomfortable / compact.
Has FooterBooleanfooter
Has HeaderBooleanheaderOptional top region for logo / app name. Separate from anatomy because it is not always present and is not a single canonical slot.
Item CountVariantitems.lengthFigma exposes 4/8/12/16+ item counts for preview; code accepts arbitrary item arrays.
Has GroupsBooleangroupsToggles whether items render as flat list or are categorised into labelled groups.
Active ItemVariantactiveItemIdFigma exposes "first / second / third item active" as Variant for preview; in code this is route-derived (current URL) or controlled prop.
Designer

Motion

TransitionDuration token
expandTogglemotion.duration.base
itemHovermotion.duration.fast
Easing
motion.easing.standard
Reduced motion
Instant (jump cut)
Designer

Responsive behaviour

BreakpointChange
breakpoint.mdAt and below, the sidebar collapses to an off-canvas Drawer pattern — invisible by default, summoned via a hamburger MenuButton trigger in the page header. The Drawer's `variant: navigation` is the canonical modal-mobile-sidebar pattern. Above `breakpoint.md` the sidebar is persistent.
breakpoint.lgAbove this width, the authored variant (expanded vs collapsed) renders persistently. Some apps use breakpoint.xl as the auto-expand threshold (compact sidebars on tablet, expanded on desktop); others leave it as a user preference toggled via the collapsible affordance.
Both

Internationalisation

RTL · mirroring

Sidebar pinning moves from inline-start (visual left in LTR) to inline-start (visual right in RTL). Item icon position reverses logically. Collapse-toggle chevron points away from the sidebar (right in LTR, left in RTL); the chevron glyph itself rotates to follow. Notification badges remain at inline-end of items (visual right in LTR, visual left in RTL).

Text expansion

Item labels grow significantly in DE / RU / FI — German "Einstellungen" is twice as wide as English "Settings". Sidebar inline-size grows to fit the longest label or truncates with ellipsis (full text in `aria-label` or via Tooltip). Collapsed variant is unaffected by text expansion (icons are direction-neutral and same width). Group labels follow item-label expansion patterns.

Both

Variants, properties, states

Variants

Structurally different versions of the component.

expandedcollapsed

Properties

The same component, parameterised.

PropertyType
collapsibleboolean
hasFooterboolean
densitycomfortable | compact

States

Browser/user-driven (interactive) vs. app-driven (data).

KindStates
interactive
hoverfocus-visibleactive
data
idlecurrent-page
Both

State transitions

FromToTrigger
idlecurrent-pagePage navigation lands the user on the route owned by this nav item. The item's `aria-current="page"` is set; visual treatment changes to indicate current-page state. Other items in the sidebar lose their current-page state (only one can be active at a time).
current-pageidleUser navigates to a different page. The previously- current item loses `aria-current="page"`; the new current item gains it.
Both

Figma↔Code mismatches

  1. 01
    Figma

    SidebarNav drawn looking like vertical Tabs

    Code

    A nav landmark with anchor links navigating to URL routes

    Consequence

    Designers may use SidebarNav and Tabs interchangeably for "vertical list of links". Implementations following the Figma file may ship `role="tablist"` for what is semantically navigation; SR users hear "tab" and expect in-page panel switching, but activating navigates to a different URL. The mental model breaks.

    Correct

    Distinguish at the canonical level: SidebarNav navigates between independent pages (URLs change); Tabs switch between content panels in the same page (URL stays). The semantic distinction drives the role (`<nav>` vs `tablist`) and the DOM (anchors vs buttons-with-aria- controls).

  2. 02
    Figma

    Collapsed variant drawn with icons but no tooltip on hover

    Code

    Each item in collapsed variant has a Tooltip showing the label on hover or focus

    Consequence

    Designers compose collapsed-variant mocks with icon-only items. Implementations following the design ship without hover tooltips; pointer users hovering an icon see no label, must guess from the icon glyph. Keyboard users see no label either (focus does not reveal anything beyond the visible icon).

    Correct

    Collapsed-variant items always have a Tooltip on hover/ focus revealing the full label. The label remains in the DOM (visually-hidden) for SR users; the Tooltip is a sighted-user affordance that surfaces it visually. Document the pairing canonically.

  3. 03
    Figma

    Active page indicated by font-weight change alone

    Code

    Active page indicated by `aria-current="page"` PLUS background fill PLUS leading accent strip

    Consequence

    Designers use a single visual change (bold text) to mark active. Implementations following the design fail WCAG 1.4.1 (Use of Color and 1.3.3 Sensory Characteristics) — bold-only differentiation is not enough for SR users (without `aria-current`) and is unreliable for users with dyslexia or reduced contrast vision.

    Correct

    Triple-layer active-state differentiation: visual (background fill + leading accent stripe + text colour shift), accessible state (`aria-current="page"`), and typography (font-weight increase). The `aria-current="page"` is the source of truth; visuals reinforce.

  4. 04
    Figma

    Sidebar drawn at fixed-width with no overflow handling

    Code

    Sidebar with internal scroll for overflow; main content scrolls independently

    Consequence

    Designers fix the sidebar at one screen-height (typical desktop mock at 1080p). Implementations following the design break on shorter viewports — items below the fold are clipped, with no scroll affordance. Mobile especially affected.

    Correct

    Sidebar's internal item region scrolls independently from main content. Footer (when present) pins to the bottom; items between header (if present) and footer scroll. Document the canonical scroll-behaviour: never truncate items silently.

Designer

Common mistakes

#sidebar-no-aria-current

Active page not marked with `aria-current`

Problem

The visual current-page state is shown (highlight, icon-fill change, accent stripe) but `aria-current` is missing from the active link. SR users hear no indication of which page they are currently on; users relying on screen reader for orientation are lost.

Fix

The active item carries `aria-current="page"` (most specific value for navigation links). SR announces "current page" before the link text. Update on every navigation.

#sidebar-collapsed-display-none-label

Collapsed variant uses `display: none` to hide labels

Problem

Implementation hides labels in collapsed variant via `display: none`. The labels are removed from the accessibility tree; SR users hear icon-only links with no accessible name (the icon's aria-hidden is correct but now there is nothing else for the link's name).

Fix

Hide labels via the `sr-only` / clip-path technique that keeps content in the accessibility tree but visually removes it. The link's accessible name remains the label text; SR users hear "Settings, link" while pointer users see only the icon.

#sidebar-as-menubutton

Sidebar implemented as a Menu (role="menu")

Problem

Implementation uses `role="menu"` and `role="menuitem"` on the sidebar items. SR users hear "menu" and expect menu-keyboard semantics (ArrowKeys auto-activate); activation navigates to a URL, breaking the menu's "select one command" mental model. Tab is captured by menu semantics rather than allowing escape.

Fix

SidebarNav uses `<nav>` with anchor links (or a `<ul>` of `<li>` containing `<a>`). Not menu, not menuitem, not menubutton. Tab navigates through items as independent links; ArrowKeys are not bound canonically (Polaris and Spectrum do bind them as an enhancement, but it is optional, not required by APG).

#sidebar-mobile-no-collapse

Sidebar always rendered on mobile

Problem

Sidebar takes 240px of viewport width on a 360px-wide mobile device. Main content gets 120px and is unusable. Or sidebar collapses to icon-only without trigger to re-expand.

Fix

On mobile (and below `breakpoint.md`), sidebar collapses to an off-canvas Drawer pattern — invisible by default, summoned via a trigger (typically a hamburger menu-button in the page header). The Drawer becomes the sidebar at narrow widths. Document the responsive transition to Drawer in `responsive.breakpoints`.

Accessibility hints
Slot Accessibility hint
root Apply `<nav>` element with `aria-label="Primary"` (or equivalent — for apps with multiple navigations, label each distinctly). The nav landmark allows SR users to jump here via landmark navigation. Avoid stacking multiple `aria-label="Navigation"` regions on the same page; each should have a distinguishing label.
group Group is a structural grouping. The group label inside is a heading element (commonly h3 or h4 depending on document outline) when the label conveys hierarchical structure; or `aria-labelledby` referencing a non-heading label.
group-label Heading element when the label carries hierarchical meaning. Visually-hidden in collapsed variant via clip-path or sr-only class — never `display: none` (which removes from SR tree).
item Real `<a href="...">` with the target route. The currently-active item carries `aria-current="page"` — SR announces "current page" before the link text. Avoid `aria-current="true"` (less specific) or bespoke `data-active` (no SR signal). Disabled links are rendered as plain text or as `<a>` with `aria-disabled="true"` plus removed `href`.
item-icon Decorative when paired with a visible label (`aria-hidden="true"`). For collapsed variant where the label is visually-hidden, the icon is still decorative because the visually-hidden label remains in the DOM for SR users — the icon never needs an aria-label for collapsed-variant nav items.
item-label Plain text. The nav item's accessible name. In collapsed variant, hide visually with sr-only / clip- path technique — NEVER `display: none` (which removes from accessible tree, leaving an icon-only link with no accessible name).
badge For numeric badges, append the count to the link's accessible name via visually-hidden text or `aria-label` composition ("Inbox, 3 unread"). Decorative-only badges (a pulse for "new") use `aria-hidden="true"` with the link's accessible name carrying the meaning explicitly ("Settings (new)").
footer Footer content is part of the sidebar's nav landmark but acts as a sub-region. For user-account flyouts, the footer typically hosts a MenuButton (avatar + dropdown). For static info, plain content is sufficient.