MiHCM
layout/@mihcm/ui·v0.21.0·stable

Sidebar

Composable, collapsible sidebar with mobile sheet support, keyboard shortcuts (Ctrl/Cmd+B), and cookie persistence.

Sidebar

A composable application sidebar for persistent navigation. It handles desktop collapse state, mobile sheet rendering, keyboard toggling, and the named navigation landmark.

When to use

  • App shells with persistent navigation alongside main content.
  • Admin dashboards with grouped menu sections.
  • Navigation panels for multi-page applications.
  • IDE layouts with file trees or tool panels.

When NOT to use

  • For landing pages — use a simple navbar.
  • For simple websites with few pages — use top navigation.
  • For mobile-first layouts — consider a bottom tab bar instead.

Import

import {
  Sidebar,
  SidebarProvider,
  SidebarHeader,
  SidebarContent,
  SidebarGroup,
  SidebarGroupLabel,
  SidebarMenu,
  SidebarMenuItem,
  SidebarMenuButton,
  SidebarInset,
  SidebarTrigger,
} from '@mihcm/ui/Sidebar';

Basic usage

Wrap everything in SidebarProvider. Place Sidebar and SidebarInset as siblings.

<SidebarProvider>
  <Sidebar>
    <SidebarHeader>…</SidebarHeader>
    <SidebarContent>
      <SidebarGroup>
        <SidebarMenu>
          <SidebarMenuItem>
            <SidebarMenuButton>Dashboard</SidebarMenuButton>
          </SidebarMenuItem>
        </SidebarMenu>
      </SidebarGroup>
    </SidebarContent>
  </Sidebar>
  <SidebarInset>
    <SidebarTrigger />
    <main>…</main>
  </SidebarInset>
</SidebarProvider>

Collapsible modes

Control how the sidebar collapses via the collapsible prop on SidebarProvider. Sidebar also accepts the prop as a visual override, but the provider is the shared source of truth for triggers, rails, keyboard shortcuts, and persisted state.

  • "offcanvas" — slides off-screen entirely (default).
  • "icon" — shrinks to an icon-only rail.
  • "none" — fixed, cannot be collapsed. The trigger stays disabled and reports aria-expanded="true".
<SidebarProvider collapsible="icon">
  <Sidebar>…</Sidebar>
  <SidebarInset>
    <SidebarTrigger />
  </SidebarInset>
</SidebarProvider>

Responsive behavior

SidebarProvider switches to mobile Sheet mode below the configured breakpoint. In mobile mode, the persistent desktop panel is replaced by a temporary overlay from the configured side.

<SidebarProvider
  mobileBreakpoint={768}
  mobileWidth="18rem"
  side="left"
>
  <Sidebar>…</Sidebar>
  <SidebarInset>
    <SidebarTrigger />
  </SidebarInset>
</SidebarProvider>

For documentation previews, tests, and design reviews, pass mobile to force mobile behavior without resizing the browser. Add defaultOpenMobile when the preview should show the drawer open immediately:

<SidebarProvider mobile defaultOpenMobile mobileWidth="calc(100dvw-2rem)">
  <Sidebar>…</Sidebar>
  <SidebarInset>…</SidebarInset>
</SidebarProvider>

Mobile capabilities:

  • Uses Sheet for focus management, backdrop dismissal, and Escape close.
  • Keeps SidebarTrigger in the content header so users can always reopen the menu.
  • Respects side="left" and side="right" for the drawer edge.
  • Uses mobileWidth independently from desktop width, so narrow screens are not forced into a desktop panel size.
  • Supports controlled mobile state with openMobile and onOpenMobileChange when the app shell needs to sync the drawer with route changes or analytics.

Side placement

Set side="left" (default) or side="right" on SidebarProvider to position the sidebar and keep triggers/rails aligned with the same side.

<SidebarProvider side="right">
  <Sidebar>…</Sidebar>
  <SidebarInset>…</SidebarInset>
</SidebarProvider>

When docked right, place SidebarTrigger on the right side of the content header and let the sidebar draw its divider on the left edge. The default sidebar variant handles the divider automatically.

Layout position

position="contained" is the default. It keeps the sidebar inside the provider flex layout, so it works correctly in application shells, split panes, documentation previews, and embedded configurators. Use position="fixed" only when the sidebar should pin to the browser viewport.

<SidebarProvider position="contained" side="right" collapsible="icon">
  <Sidebar>…</Sidebar>
  <SidebarInset>…</SidebarInset>
</SidebarProvider>

Composition

  • Use SidebarProvider at the layout root to manage open/collapsed state and shared layout configuration.
  • SidebarMenu, SidebarMenuItem, SidebarMenuButton build the navigation list.
  • SidebarGroup with SidebarGroupLabel organizes items into named sections.
  • SidebarFooter anchors settings, help, or user profile links at the bottom.
  • Use width, iconWidth, and mobileWidth on SidebarProvider for layout sizing instead of hard-coded utility widths on child nodes.

Accessibility notes

  • Sidebar renders as a named <nav> landmark by default.
  • SidebarTrigger keeps aria-expanded in sync with the current open state. With collapsible="none", it is disabled because there is no valid collapsed state.
  • Use aria-current="page" on the active SidebarMenuButton when it represents the current route.
  • Use tooltip on icon-rail menu buttons so collapsed labels remain available.
  • Main Sidebar — compact app rail with responsive mobile menu.
  • Sheet — temporary overlay panels.
  • PageShell — layout wrapper that positions sidebar and content.
  • NavigationMenu — horizontal navigation alternative.