Askr
UI & Components

Sidebar

Use sidebar with the current published Askr packages.

  • @askrjs/themes/sidebar0.0.13

How to use sidebar

Sidebar should use the standard themed surface unless the application is deliberately implementing its own design system on top of @askrjs/ui.

  1. Import the themed component from @askrjs/themes/components; use @askrjs/ui directly only when building a custom visual system.
  2. Keep sidebar labels, state, and application actions visible at the call site instead of styling internal DOM nodes.
  3. Verify keyboard behavior, focus movement or return, disabled state, and both standard themes.
import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem } from '@askrjs/themes/components';

<Sidebar>
  <SidebarContent>
    <SidebarGroup><SidebarGroupLabel>Workspace</SidebarGroupLabel>
      <SidebarMenu><SidebarMenuItem><SidebarMenuButton active>Projects</SidebarMenuButton></SidebarMenuItem></SidebarMenu>
    </SidebarGroup>
  </SidebarContent>
</Sidebar>

Purpose

Sidebar covers the collapsible side-navigation panel pattern common in dashboards and admin tools, and it's styled entirely at the theme layer — @askrjs/ui doesn't define a headless version to build on. What you get is a family of layout parts (header, content, footer, groups, menu items) alongside a trigger button, all presentational rather than stateful. Use it for persistent app chrome; for anything transient or overlay-based, Dialog, Sheet, or Popover are the better fit.

Install and import

Import Sidebar and its parts (SidebarContent, SidebarHeader, SidebarFooter, SidebarGroup, SidebarMenu, SidebarMenuItem, SidebarMenuButton, SidebarTrigger, and more) from @askrjs/themes/sidebar, which resolves to the same shared components barrel as every other themes subpath. There's no separate @askrjs/ui/sidebar to install — the whole component lives in @askrjs/themes.

Live examples

A common layout wraps SidebarScope around a Sidebar and a SidebarInset (the main content area), with the Sidebar itself built from SidebarHeader, SidebarContent (holding one or more SidebarGroup blocks), and a SidebarFooter. Inside a group, SidebarMenu is a ul of SidebarMenuItem entries, each rendering a SidebarMenuButton and optionally a SidebarMenuAction or SidebarMenuBadge alongside it. SidebarTrigger is the button you place in your header or toolbar to toggle the sidebar open or closed.

Anatomy

The nesting is SidebarScope > (Sidebar, SidebarInset), with Sidebar itself made of SidebarHeader, SidebarContent > SidebarGroup > (SidebarGroupLabel, SidebarGroupContent > SidebarMenu > SidebarMenuItem), and SidebarFooter. SidebarRail is a thin edge-of-sidebar button for toggling or resizing, and SidebarTrigger is a standalone button meant to live outside the sidebar itself, typically in a top bar. Every part accepts `as` and `asChild` so you can swap the underlying element without losing the styling hooks.

State model

None of this is stateful — Sidebar has no internal open/collapsed flag; `collapsible`, `side`, and `variant` are plain props you pass in based on state you own elsewhere (a boolean in your app, a cookie, whatever fits). SidebarTrigger and SidebarRail render as buttons with no click behavior baked in, so wiring their onClick to actually toggle your sidebar state is on you. This is a deliberate consequence of Sidebar being themes-only: there's no headless controller underneath managing collapse for you.

Keyboard and accessibility

Sidebar renders as a real aside element and SidebarMenu as a ul/li list, which gives you reasonable landmark and list semantics for free, and SidebarTrigger/SidebarRail render as native button elements so they're keyboard-focusable and activatable out of the box. Beyond that baseline, there's no ARIA wiring for collapsed/expanded state (no aria-expanded is set automatically) — if your sidebar toggles visibility, you'll want to add that attribute yourself based on the state driving `collapsible`. The `tooltip` and `tooltipSide` props on SidebarMenuButton, SidebarMenuAction, and SidebarTrigger set data-tooltip/data-tooltip-side attributes for the theme's tooltip styling, but don't wire up ARIA labeling on their own.

Styling and tokens

Everything styles through [data-slot="sidebar"] and its part-specific siblings, with data-variant ("sidebar" | "floating" | "inset"), data-side ("left" | "right"), and data-collapsible reflecting whatever you passed as props. The floating and inset variants add margin, border, and radius on top of the base sidebar look, both reading from the same --ak-color-border, --ak-space-sm, and --ak-radius-lg tokens used throughout the theme. SidebarMenuButton additionally sets data-active and data-size/data-variant so you can style the current selection and size variants without extra classes.

API

Sidebar's own props are `collapsible` ("offcanvas" | "icon" | "none"), `side` ("left" | "right"), `variant` ("sidebar" | "floating" | "inset"), plus `width` and `shrink` inherited from the underlying Block layout primitive. SidebarMenuButton, SidebarMenuAction, and SidebarTrigger share button-flavored props — `active`, `size` ("default" | "sm" | "lg"), `variant` ("default" | "outline"), `tooltip`, and `tooltipSide` ("top" | "bottom" | "left" | "right"). The remaining parts (SidebarContent, SidebarHeader, SidebarFooter, SidebarGroup, and friends) take generic element props with no component-specific additions.

Edge cases

Because collapse state isn't managed internally, an "offcanvas" sidebar that's supposed to slide off-screen only does so if your CSS and state actually respond to whatever flag you're toggling — the `collapsible` prop alone doesn't hide anything by itself beyond setting the data-collapsible attribute. If you use the "icon" collapsible mode, you're responsible for swapping label visibility and layout at whatever breakpoint or state change you define; nothing here does that automatically. Nesting multiple SidebarGroup sections is fine, but deeply nested menus aren't part of the shipped structure — SidebarMenuItem doesn't support nested SidebarMenu out of the box.

Application Chrome and Application Layout cover how Sidebar fits into a full page shell alongside a Navbar or Header. For the toggle button pattern itself independent of sidebar-specific styling, Button covers the underlying variants SidebarTrigger builds on. If what you actually need is in-page section switching rather than persistent app navigation, look at Tabs or Accordion and Collapsible instead.