Sidebar

The persistent navigation panel used in this docs shell. Renders a collapsible nav tree from the navigation.ts data source, with a search trigger and mobile drawer behaviour.

Anatomy

ZoneContents
Logo headerSitka wordmark + version badge. Height matches --header-height (52px).
Search triggerGhost button that calls onSearchOpen, which opens CommandPalette. Shows ⌘K shortcut.
Nav treeScrollable list of NavSection → NavGroup → NavItem. Groups are collapsible with ChevronRight indicators.
FooterBranding strip at the bottom of the sidebar.

Data source

The nav tree is driven by the navigation export from @/lib/navigation.ts. The hierarchy is:

TypeDescriptionRequired fields
NavSectionTop-level category labeltitle
NavGroupCollapsible sub-group within a sectiontitle, items
NavItemIndividual nav linktitle, href

NavItem also accepts an optional badge string (e.g. “New”, “Gold Standard”) and an external boolean.

Layout tokens

TokenValueDescription
--sidebar-width220pxFixed width of the sidebar panel
--header-height52pxHeight of the logo row, shared with the top header

Mobile behaviour

  • On screens narrower than md (768px) the sidebar is off-screen (translateX(-100%)) by default.
  • It slides in via CSS transition when isOpen is true, overlaying the content with a semi-transparent backdrop.
  • The backdrop click calls onClose; a close button (X icon) is rendered inside the sidebar header on mobile.
  • On desktop (md+) the sidebar is always visible and the isOpen prop has no effect.

Implementation

Sidebar.tsx
tsx
"use client";
// The Sidebar is used in the docs shell layout at
// src/components/layout/Sidebar.tsx
//
// It reads from src/lib/navigation.ts to render the nav tree.
// NavSection → NavGroup → NavItem hierarchy.
//
// Integrate it in your layout:
import { Sidebar } from "@/site/layout/Sidebar";

export default function DocsLayout({ children }: { children: React.ReactNode }) {
  const [menuOpen, setMenuOpen] = useState(false);
  const [searchOpen, setSearchOpen] = useState(false);

  return (
    <div style={{ display: "grid", gridTemplateColumns: "var(--sidebar-width) 1fr" }}>
      <Sidebar
        isOpen={menuOpen}
        onClose={() => setMenuOpen(false)}
        onSearchOpen={() => setSearchOpen(true)}
      />
      <main>{children}</main>
    </div>
  );
}

Props

PropTypeDefaultDescription
isOpenbooleanWhether the sidebar is visible on mobile. On desktop (md+) the sidebar is always visible.
onClose() => voidCalled when the mobile backdrop is clicked or the close button is pressed.
onSearchOpen() => voidCalled when the search trigger inside the sidebar is clicked.

Accessibility

  • The sidebar renders as <aside> — a complementary landmark, available in screen reader quick-navigation shortcuts.
  • Navigation links are wrapped in <nav>, making them another accessible landmark.
  • Group toggle buttons use aria-expanded to communicate collapsed/expanded state.
  • Active links receive aria-current="page" via the data-active class pattern (handled by NavLinkItem).
  • The mobile close button has aria-label="Close navigation".