Navigation · astro-ui · SidebarNew

Sidebar

Side navigation shell with header, grouped links, and a footer.

Sidebar is a <nav> landmark with three regions: a header for the product or workspace switcher, a scrollable body of SidebarGroup and SidebarItem children, and a footer for the user menu. Groups can be static or collapsible through native <details>, so a long navigation tree expands and collapses without any JavaScript. Collapsing the whole sidebar to an icon rail is application state, not a visual variant, and is left to the app.

Features

  • Attached (flush) or floating (stand-off) surfaces
  • Optional sticky positioning and a scrollable body
  • SidebarGroup: static groups or native `<details>` disclosures
  • SidebarItem: links or action buttons, icons, badges, nested indent
  • `active` maps to `aria-current="page"` on links and buttons, not a class
  • Header and footer slots for brand and user menus

Usage

---
import { Sidebar, SidebarGroup, SidebarItem } from "astro-ui";
---

<Sidebar ariaLabel="Project">
  <div slot="header">Acme</div>
  <SidebarGroup label="Workspace">
    <SidebarItem href="/overview" active>Overview</SidebarItem>
    <SidebarItem href="/deploys" badge="3">Deploys</SidebarItem>
  </SidebarGroup>
  <div slot="footer">ada@acme.dev</div>
</Sidebar>

Demos

Workspace sidebar

<Sidebar ariaLabel="Project" sticky>
  <div slot="header">
    <Avatar size="sm">AC</Avatar>
    <span>Acme Inc.</span>
  </div>
  <SidebarGroup label="Workspace">
    <SidebarItem href="#overview" active>
      <span slot="icon" aria-hidden="true">◎</span>
      Overview
    </SidebarItem>
    <SidebarItem href="#deploys" badge="3">
      <span slot="icon" aria-hidden="true">⇡</span>
      Deploys
    </SidebarItem>
    <SidebarItem href="#settings">
      <span slot="icon" aria-hidden="true">⚙</span>
      Settings
    </SidebarItem>
  </SidebarGroup>
  <div slot="footer">ada@acme.dev</div>
</Sidebar>

Collapsible groups

<Sidebar ariaLabel="Docs">
  <SidebarGroup label="Getting started" collapsible open>
    <SidebarItem href="#install">Install</SidebarItem>
    <SidebarItem href="#tokens">Tokens</SidebarItem>
  </SidebarGroup>
  <SidebarGroup label="Components" collapsible>
    <SidebarItem href="#button">Button</SidebarItem>
    <SidebarItem href="#menu">Menu</SidebarItem>
  </SidebarGroup>
</Sidebar>

Client-routed action rows

<Sidebar ariaLabel="Views">
  <SidebarGroup label="Views">
    <SidebarItem active>
      <span slot="icon" aria-hidden="true">◎</span>
      Overview
    </SidebarItem>
    <SidebarItem>
      <span slot="icon" aria-hidden="true">☰</span>
      Members
    </SidebarItem>
    <SidebarItem disabled>Billing (soon)</SidebarItem>
  </SidebarGroup>
</Sidebar>

Without an href, SidebarItem renders a real button — use it for client-routed views. active still exposes aria-current="page".

Floating with nested items

<Sidebar variant="floating" ariaLabel="Files">
  <div slot="header">Files</div>
  <SidebarGroup label="Source">
    <SidebarItem href="#src">src</SidebarItem>
    <SidebarItem href="#components" nested>components</SidebarItem>
    <SidebarItem href="#styles" nested>styles</SidebarItem>
    <SidebarItem href="#locked" disabled>archive (read-only)</SidebarItem>
  </SidebarGroup>
</Sidebar>

API

Props

PropTypeDefaultDescription
variant"attached" | "floating""attached"Surface treatment.
stickybooleanfalseStick to the viewport while content scrolls.
ariaLabelstring"Sidebar"Accessible name for the navigation landmark.
classstring—Merged via cn(); Tailwind classes welcome.
idstring—Element id.
ariaLabelstring—Accessible name.

Slots

SlotDescription
headerBrand or workspace switcher.
(default)SidebarGroup and SidebarItem children.
footerUser menu or account row.

Accessibility

Implemented accessibility features — semantics, ARIA wiring, and keyboard behavior that ship with the component.

  • Root is a <nav> landmark named by ariaLabel
  • Groups use role="group" with aria-labelledby, or <summary> when collapsible
  • Current page is exposed with aria-current="page" in both link and button rows
  • Disabled items use aria-disabled and drop their href
  • Collapsible groups are native <details> — no keyboard handler to get wrong

FAQ

How do I build the mobile drawer version?

Render the same groups inside `Sheet side="left"` and trigger it from a Navbar button. The sidebar itself stays hidden below your breakpoint; `Sheet` already owns the dialog focus trap.

Can I collapse it to an icon rail?

Not as a prop. Rail/collapsed state is application state: hide the labels yourself (a `data-collapsed` attribute on the nav plus your own CSS), and keep the accessible name on each item so the rail stays usable.

What props does SidebarItem take?

`href`, `active`, `disabled`, `badge`, `nested`, `class`, `id`, plus an `icon` slot. `active` renders `aria-current="page"` on links and buttons alike.

When do I use a button row instead of a link?

When navigation happens client-side (a view switcher, a filter, a drawer toggle). Omit `href` and SidebarItem renders `<button type="button">`, so keyboard activation and form-less behavior stay native.

Changelog

Version history mentioning Sidebar.

v0.1.0 — 2026-11-11
added
  • Navigation (7): Tabs, Breadcrumb, Pagination, Stepper, Tree, Navbar, Sidebar.