components / sidenav

SideNav

Two-level application shell navigation with active-state emphasis, branch expansion, and a collapsed mode.

Overview

What it is

This section explains the intent of the component before the implementation details.

  • SideNav is the shell-level navigation surface for structured app areas and nested sections.
  • It prioritizes strong active-state emphasis, predictable expansion, and keyboard movement through the visible hierarchy.

Aliases

sidebar navigation

Decision guide

How to choose it

Use these notes to decide quickly whether this is the right DK component for the job.

Decision guide

  • Choose SideNav when the interaction should feel deliberate, documented, and reusable across product surfaces.
  • If the scenario is more specialized than the current SideNav contract, prefer a simpler component or build a dedicated workflow on top of the lower-level DK primitives.

Do

  • Keep the SideNav label, value, or status language direct enough to scan quickly.
  • Use the documented size and state recipes instead of inventing one-off variants in product code.

Do not

  • Do not hide the main purpose of SideNav behind decorative copy or overloaded surface treatments.
  • Do not stretch SideNav into a workflow it was not designed to handle just because the visuals are close.

Usage

When to use

Prefer these situations when choosing this component.

  • Use SideNav for persistent app-section navigation, especially when the app has a strong hierarchy.
  • Use the collapsed mode when shell density matters more than always-visible labels.

Usage

When not to use

These patterns are better served by a different component or a simpler surface.

  • Do not use SideNav for one-off subsection navigation inside a content page.
  • Do not treat it like a breadcrumb or progress indicator.

Anti-patterns

  • Using SideNav as a generic layout container instead of a purpose-built interaction or content surface.
  • Forking the documented recipe in product code instead of extending the shared DK contract.

Migration notes

  • Migrate legacy sidenav usage by mapping existing variants and states onto the documented DK props before porting any custom styling.
  • Treat the docs examples as the reference contract for accessibility and event behavior during adoption.

Anatomy

Structural parts

The anatomy explains which pieces matter to the recipe and accessibility model.

nav row

item

Single navigation destination or expandable parent.

expand/collapse affordance

branch

Toggles nested child visibility.

auxiliary status

badge

Optional compact count or state marker.

API

Public interface

The docs contract distinguishes props, DOM events, and slots so integration behavior is explicit.

Props

NameTypeDefaultDescription
itemsArray<{ id: string; label: string; href?: string; icon?: string; badge?: string; disabled?: boolean; children?: SideNavItem[] }>Navigation tree with at most two visible levels in the current contract.
activeIdstringControlled active navigation id.
collapsedbooleanfalseEnables the denser collapsed shell mode.
onChange(detail: { id: string }) => voidCallback fired when the active navigation item changes.
themeThemeContractOverrides the compiled DK theme used to resolve tokens and recipes for this component.

Events

NamePayloadDescription
change{ id: string }Fires when the active item changes.

Slots

NameDescription
defaultSideNav is data-driven in v1 and does not expose item slots.

Recipes

Variants, sizes, and states

These notes summarize the intended recipe surface rather than exposing raw implementation detail first.

Variants

  • expanded: Full labels and nested branch state are visible.
  • collapsed: Top-level items compress into a denser shell mode.

Sizes

  • default: SideNav uses one shell density tuned for application navigation.

States

  • rest: Inactive navigation row
  • selected: Current route or section
  • expanded: Parent branch is open

Accessibility

Accessibility contract

This is the behavior the component promises to assistive tech and keyboard users today.

Semantics

  • Uses navigation semantics with explicit active and expanded state cues.

Keyboard

  • Arrow keys move through visible items, Right expands, Left collapses or moves to the parent, and Enter activates the row.

Screen readers

  • Branch state, current location, and disabled state remain explicit through the row semantics.

Checklist

  • Verify the visible label or title still produces a clear accessible name.
  • Verify focus remains obvious in every supported state and size.
  • Verify disabled, selected, and error states do not rely on color alone.

Implementation

Tokens and slot vars

This section shows the representative compiled slot variables that the runtime consumes for the selected design system.

root

--dk-side-nav-bg
#e5e8ed
--dk-side-nav-fg
#16181c
--dk-side-nav-border
#95989d
--dk-side-nav-gap
0.4rem
--dk-side-nav-padding
0.75rem

item

--dk-side-nav-item-bg
#e5e8ed
--dk-side-nav-item-fg
#16181c
--dk-side-nav-item-radius
clamp(0.75rem, 0.6875rem + 0.278vw, 0.938rem)
--dk-side-nav-item-min-height
44px
--dk-side-nav-item-inline-padding
0.75rem

label

--dk-side-nav-label-size
0.92rem
--dk-side-nav-label-weight
600

badge

--dk-side-nav-badge-size
0.75rem

branch

--dk-side-nav-branch-size
0.85rem

Implementation notes

  • SideNav is capped at two levels in v1 to keep the shell predictable and keyboard scanning simple.

Implementation checklist

  • Use the public component API first and only drop to lower-level primitives when the component contract genuinely does not fit.
  • Keep theme overrides token-driven so proofs and recipes stay meaningful.
  • Verify the shipped examples and proof fixtures still represent the real product scenario you are implementing.

Examples

Copy-paste examples

Each example is intentionally practical, grouped by starter, common pattern, and edge-case coverage.

Examples
3
Depth
expanded

Starter

1 example

starter

Starter: app shell navigation

A persistent shell navigation with one expanded branch.

Copy snippet

<SideNav items={navItems} activeId="overview" onChange={(detail) => activeId = detail.id} />

Common patterns

1 example

common

Common: collapsed shell mode

Collapsed mode keeps the app shell lighter while preserving the active section marker.

Copy snippet

<SideNav items={navItems} activeId="overview" collapsed={true} />

Edge cases

1 example

edge

Edge: navigation with counts

Badges can call attention to queues or inbox-like sections without changing the base navigation contract.

Copy snippet

<SideNav items={[{ id: 'inbox', label: 'Inbox', badge: '12' }, { id: 'releases', label: 'Releases', children: [{ id: 'planned', label: 'Planned' }] }]} activeId="inbox" />

Verification

Curated proof fixtures

Proofs stay visible in the docs so the system shows what it can guarantee, not just what it can render.

default

pass

  • Contrast: 90.8 Lc
  • Target: 44px
  • Layout: 0 / 240, 320

selected

pass

  • Contrast: 89.9 Lc
  • Target: 44px
  • Layout: 0 / 240, 320