Sidebar Nav
Collapsible side navigation with grouped sections, accordion children, badges, and a collapse-to-rail toggle. A Lit web component, because the collapse and accordion states are real runtime behavior.
Preview
Use the chevrons button at the top to collapse to an icon rail; click Reports to expand its children.
<esa-sidebar-nav id="demo"></esa-sidebar-nav>
<script>
const el = document.getElementById('demo');
el.items = [
{ label: 'Dashboard', href: '/dashboard', active: true, group: 'Main' },
{ label: 'Projects', href: '/projects', badge: 12, group: 'Main' },
{ label: 'Reports', group: 'Main', children: [
{ label: 'Monthly', href: '/reports/monthly' },
{ label: 'Quarterly', href: '/reports/quarterly' },
] },
{ label: 'Team', href: '/team', group: 'Admin' },
{ label: 'Billing', href: '/billing', group: 'Admin', disabled: true },
{ label: 'Settings', href: '/settings', group: 'Admin' },
];
</script> States
Non-collapsible — set collapsible="false" to hide the toggle and lock the sidebar at full width.
<esa-sidebar-nav id="demo2" collapsible="false"></esa-sidebar-nav> API
| Prop | Type | Default | Description |
|---|---|---|---|
items | EsaSidebarNavItem[] | [] | Nav items (property, set via JS). Each is { label; href?; icon?; badge?; children?; disabled?; group?; active? }. Consecutive items sharing a group render under a group heading. |
label | string | 'Sidebar' | Accessible name for the navigation landmark. Do not include the word "navigation" — the role is announced with it. Give two rails on one page distinct labels so the landmark list can tell them apart. |
collapsed | boolean | false | Collapses to an icon rail. Reflected as an attribute. |
collapsible | boolean | true | Shows the collapse toggle. Set false to lock the sidebar open. On by default. Write `="false"` to turn it off — unusually for a boolean attribute, this one reads the value. |
drawer | boolean | false | Drawer mode: the rail becomes a slide-out overlay instead of an in-flow column, for narrow viewports. esa-app-shell sets this from a matchMedia. The <nav> landmark stays on the page in both modes — only its contents hide — and the toggle stays inside the landmark, so navigating to it while shut lands on the control that opens it. |
drawer-open | boolean | false | Whether the drawer is shown. Only meaningful with drawer. While open, the drawer emits drawerchange so the host can make the rest of the page inert. Property: `drawerOpen`. |
Events
| Event | Type | Default | Description |
|---|---|---|---|
collapsedchange | CustomEvent | — | Fired when the collapse toggle is clicked. detail: { collapsed: boolean }. Bubbles and composed. |
Binding these events from Angular
Every one of these is a CustomEvent, so the payload is on
$event.detail — $event.target.value reads empty, with no
error. The names are lowercase and Angular passes them to
addEventListener verbatim, so camel-casing one means it never fires.
(collapsedchange)="onCollapsedchange($event.detail)"(drawerchange)="onDrawerchange($event.detail)"
items is an array property — set it in JS, not as an attribute. Each EsaSidebarNavItem.icon is a raw inline SVG string.
Slots
| Prop | Type | Default | Description |
|---|---|---|---|
header | slot | — | Logo / brand area pinned above the nav list. |
Accessibility
- Renders a
<nav aria-label="Sidebar navigation">over a semantic list. - Active leaf links carry
aria-current="page"; parent accordions exposearia-expanded. - The collapse toggle's
aria-labelflips betweenCollapse sidebar/Expand sidebar. - Disabled items are removed from the tab order (
tabindex="-1",pointer-events: none).