Side menu · navigation drawer
A complete app sidebar: search, folding groups, nested items, badges and a marker that glides to the current page — it folds to an icon rail on wide screens and becomes a swipeable drawer behind a top bar on phones.
Wide · search (press /) · groups fold · nested items · fold it to an icon rail with the button top-right
Home
Content for home. Pick another item — the marker glides to it.
Phone · ☰ opens the drawer · tap outside, Esc or swipe it left to close
Inbox
Content for inbox. Pick another item — the marker glides to it.
This site's own menu on the left is the same component — narrow the window below 900px to get the top bar and the drawer.
Usage
import { signal, html } from "./index.js";import { SideMenu } from "./components/sidemenu.js"; const page = signal("home");SideMenu({ brand: html`<b>◆ Acme</b>`, search: true, // "/" focuses it; Enter opens the first match sections: [ { items: [{ id: "home", label: "Home", icon: homeIcon, href: "/" }, { id: "inbox", label: "Inbox", icon, href: "/inbox", badge: "12" }] }, { title: "Workspace", items: [ // titled groups fold (remembered) { id: "projects", label: "Projects", icon, children: [{ id: "web", label: "Website", href: "/p/web" }] }, { id: "reports", label: "Reports", icon, href: "/reports", badge: Badge({ label: "New" }) } ] }, ], active: page, // its group and parent open by themselves onNavigate: (item, e) => { e.preventDefault(); navigate(item.href); }, footer: userCard, header: workspaceSwitcher, actions: avatar, // actions: the phone top bar})// wide: sticky, folds to an icon rail · under 900px: a top bar + a drawer (focus trap, Esc, swipe)