Headless Core — Sidebar
Powers Sidebar internally. Compare with
Navbar: same active-item-tracking core, but oriented
vertically (ArrowUp/ArrowDown instead of ArrowLeft/ArrowRight), with a
collapse toggle instead of scroll-spy/route detection, and items split into
main/bottom sections instead of a single flat list.
import { createSidebar } from '@andersseen/headless-components/sidebar';
const sidebar = createSidebar({ items: [ { id: 'home', label: 'Home', icon: 'home' }, { id: 'settings', label: 'Settings', icon: 'settings', section: 'bottom' }, ], defaultActiveItem: 'home', onActiveItemChange: id => console.log('Active:', id),});
sidebar.actions.toggleCollapse();Config
Section titled “Config”| Option | Type | Default | Notes |
|---|---|---|---|
items | SidebarItemDef[] | [] | { id, label, icon?, disabled?, section? }; section is 'main' (default) or 'bottom'. |
defaultActiveItem | string | 'home' | |
onActiveItemChange | (id: string) => void | — | |
defaultCollapsed | boolean | false | |
onCollapsedChange | (collapsed: boolean) => void | — | |
mobileCollapse | boolean | true | Only affects the initial mobileCollapsed state — see below. |
ariaLabel | string | 'Sidebar navigation' |
activeItem, collapsed, mobileCollapsed — note mobileCollapsed is
initialized from config.mobileCollapse !== false but nothing in this factory
ever changes it afterward except actions.setMobileCollapsed; actually
detecting “we’re on mobile” (a media query) is the consuming component’s job.
Actions
Section titled “Actions”setActiveItem(id), toggleCollapse() / setCollapsed(v),
setMobileCollapsed(v), setItems(items) (re-registers the list; doesn’t reset
activeItem the way Navbar’s setItems does).
Queries
Section titled “Queries”isActive(id), isCollapsed(), isMobileCollapsed(), isDisabled(id),
getMainItems() (items with no section or section: 'main'),
getBottomItems() (section: 'bottom'), getItemIds().
Prop-getters & handler
Section titled “Prop-getters & handler”| Getter | Returns |
|---|---|
getContainerProps() | role: 'navigation', aria-label, data-collapsed, data-mobile-collapsed |
getNavListProps(section?) | role: 'menu', aria-label ('Main navigation' or 'Secondary navigation' depending on section) |
getItemProps(id) | role: 'menuitem', aria-current, aria-disabled, data-active, data-state, data-collapsed, tabindex, id (sidebar-item-${id}) |
getToggleProps() | aria-expanded (inverse of collapsed), aria-label (swaps “Expand”/“Collapse”), data-collapsed, role: 'button', tabindex: 0 |
handleItemKeyDown(event, currentItemId) — ArrowDown/ArrowUp move with
wraparound (skipping disabled items), Home/End jump, Enter/Space
activate. No Escape handling (unlike Navbar — a sidebar has no mobile overlay
panel to dismiss with it).
Live example
Section titled “Live example”Next steps
Section titled “Next steps”Navbar — the horizontal counterpart, with scroll-spy and route-based active detection.