Skip to main content

AdminSidebar

Implemented

Sticky admin sidebar with a logo slot and grouped navigation lists whose active row gets aria-current and a teal accent.

Categoryorganisms
Sourcecomponents/organisms/AdminSidebar/AdminSidebar.tsx
AI HintPass AdminSidebarGroup[] plus activeId; items with href render as links and items without render as buttons firing onItemClick. Prefer the Sidebar molecule for new work (mobile drawer + focus trap — the DS-CORR-08-05 dashboard migration); formal deprecation decision PENDING — no ADR has deprecated it, status stays implemented until that ADR lands.

Sticky 247px admin sidebar with a logo slot and grouped navigation lists whose active row gets aria-current and a teal accent. For new dashboard work prefer the Sidebar molecule (portal mobile drawer with scrim + focus trap, gated on collapsible).

AdminSidebar

Organism — Admin family

Sticky w-[247px] h-screen aside with a logo slot and grouped nav lists (h3 label + role=list per group). Items with href render as real anchors; items without render as buttons firing onItemClick. The active row gets aria-current='page' + a teal left-accent; row heights honor --ep-tap-min. No mobile drawer — for responsive dashboards use the Sidebar molecule (portal drawer + focus trap; enable its collapsible prop).

Click a row — links would navigate (href="#…" here); "Exporter" has no href, so it is a button.

No button item fired yet.

This component supports light and dark mode.

Usage

Pass groups (real sections, not decoration — each heading labels its list), match activeId to the item id (never derived from the URL), and choose link vs button per item: href for real navigation, no href for panel toggles and exports. Pair with AdminLayout / AdminHeader for the full admin frame — the shell is a fixed 247px sticky column with its own scroll.

import { AdminSidebar } from '@epasslive/design-system'

const groups = [
  {
    id: 'commerce',
    label: 'Commerce',
    items: [
      { id: 'events', label: 'Événements', href: '/admin/events' },
      { id: 'orders', label: 'Commandes', href: '/admin/orders' },
    ],
  },
  {
    id: 'finance',
    label: 'Finance',
    items: [
      { id: 'payouts', label: 'Versements', href: '/admin/payouts' },
      { id: 'export', label: 'Exporter' }, // no href — button row
    ],
  },
]

<AdminSidebar
  logo={<span className="font-semibold text-ep-text-heading">ePassLive</span>}
  groups={groups}
  activeId={active}
  onItemClick={(id) => trackNav(id)}
/>

Sidebar molecule migration

For responsive or mobile dashboards use the Sidebar molecule: it owns the mobile overlay pattern (portal + scrim + focus trap + Escape + scroll lock — see the molecule's docs) that this desktop-only organism lacks. The storefront dashboard already migrated — the DS-CORR-08-05 precedent; its regression test asserts this organism's attributes are gone from dashboard surfaces. Keep AdminSidebar for desktop-only admin frames composed with AdminLayout.

The API maps directly: groups → groups: SidebarGroup[] (items gain icon, badge, nested children), activeId → activeKey, onItemClick → onItemClick (1:1, same name), and logo / className keep their names.

Two migration caveats: the defaults drift — ariaLabel "Admin primary navigation" → "Primary navigation" and id "admin-sidebar" → "sidebar" — so keeping defaults changes the accessible name and the DOM id; and the mobile drawer is gated on collapsible (default false) — without it the molecule is desktop-sticky-only too. Compose it with collapsible, as AdminLayout's docs direct, for responsive frames.

Accessibility

The sidebar is a named <aside> containing a named <nav>; each group's list is labeled by its heading via aria-labelledby (WCAG 1.3.1). The active row carries aria-current="page" (WCAG 2.4.8) alongside the teal visual accent. Row heights meet the WCAG 2.5.5 target minimum via --ep-tap-min. The empty state (no groups) renders an em-dash in an aria-live="polite" paragraph.

Props

Prop
Type
Default
Description
logo*
React.ReactNode
—

Brand slot rendered at the top of the sidebar.

groups*
AdminSidebarGroup[]
—

Nav groups — one labeled list per group (see the type tables below).

activeId
string
—

Marks the matching item as current (aria-current='page' + teal accent).

onItemClick
(id: string) => void
—

Click hook — fires for every item (links navigate AND fire; buttons only fire).

ariaLabel
string
"Admin primary navigation"

Accessible name for the aside and inner nav.

className
string
—

Class on the aside shell.

id
string
—

Stable id (defaults to admin-sidebar).

Group definition

Prop
Type
Default
Description
id*
string
—

Group identifier — keys the heading id.

label*
string
—

Group heading (rendered uppercase, small).

items*
AdminSidebarItem[]
—

The group's nav rows.

Item definition

Prop
Type
Default
Description
id*
string
—

Item identifier — matches activeId, used as React key.

label*
string
—

Row text.

href
string
—

When present the row is a real anchor; when absent it is a button type=button.

Props

Preview

AdminSidebar

Prop
Type
Required
Default
Description
logo
React.ReactNode
Required
—

Brand slot rendered at the top of the sidebar.

groups
AdminSidebarGroup[]
Required
—

Nav groups — one labeled list per group (id, label, items).

activeId
string
Optional
—

Marks the matching item as current (aria-current="page" on link rows + teal accent).

onItemClick
(id: string) => void
Optional
—

Click hook — fires for every item (links navigate AND fire; buttons only fire).

ariaLabel
string
Optional
'Admin primary navigation'

Accessible name for the inner <nav> landmark (one labelled landmark).

className
string
Optional
—

Extra classes on the <aside> shell.

id
string
Optional
'admin-sidebar'

Stable base id for the shell and group heading ids.

Quick use:<AdminSidebar />
Design System v4.1.0 | ePassLive