Skip to content
LyEve UI v0.60.1

Navigation

SidebarNav

A navigation tree of any depth, with persisted expansion, a collapsed icon rail and aria-current on the current page and each of its ancestors. It renders a <nav> and nothing else, so it drops inside the aside your app shell already owns without adding a second landmark.

Basic

The active row comes from activePath, which you pass in as a pathname. The kit cannot import your router, so nothing here reads the URL on its own.

Which row is current

A leaf answers for its own path. A node with children answers for its whole subtree, which is what lets a section say "you are somewhere in here" while its child says "you are here". So /content/posts marks the Posts row as the page and Content as an ancestor, and two sibling leaves whose paths share a prefix never mark themselves together. Set match on a node to override that, or to 'none' to opt it out of path matching entirely.

One row carries the mark at a time. While the section that holds the current page is open, the page's row is marked and the section shows its label in full text color with no bar of its own. Close that section and the section carries the mark until you open it again. A nested row is drawn exactly like a top-level row at rest, under the pointer, on focus and as the current page, with its fill and bar starting at its own indent.

A colored badge reads at 4.5:1 or better on every row: at rest, on the current page's row, and on a row under the pointer or a finger.

Collapsed rail

The rail keeps every label in the accessible name, so a row whose only visible content is an icon is still announced by name rather than as an empty link.

A row that is both a link and a group stacks its disclosure under its link, so the pair fits the rail's width and the rail never scrolls sideways. In the rail below, that is the database icon with its chevron under it. Under a touch screen the link and the disclosure each grow to the 44px control height.

Remembering what the reader closed

With a storageKey, a group the reader opens or closes stays that way across navigations and reloads. A reader decision always beats the default, so a group they closed does not reopen itself every time they move inside it. Without a key the same rule applies in memory for the life of the page. exclusive keeps one group open at a time.

API

PropTypeDefaultDescription
items requiredNavTree no defaultThe navigation tree.
activePath requiredstring no defaultPathname only, no query and no hash. Passed in, because the kit cannot import your router.
label string'Primary'Accessible name of the nav landmark.
collapsed booleanfalseIcon-only rail. Labels stay in the accessible name.
expandActive booleantrueOpen the ancestors of the current page.
exclusive booleanfalseKeep one group open at a time.
storageKey string no defaultlocalStorage key for what the reader opened and closed. Undefined keeps it in memory.
class string no defaultExtra classes on the nav element.

NavNode

PropTypeDefaultDescription
id requiredstring no defaultStable across renders. aria-controls is built from it and the list is keyed by it.
label requiredstring no defaultRow text.
href string no defaultDestination. A node without one is a section, not a link. A javascript:, data: or vbscript: URL is refused, and the row renders without a link.
icon Component no defaultA lucide component, drawn before the label.
children NavNode[] no defaultNested rows. Any depth.
badge string | number no defaultA count or a status beside the label.
badgeTone 'neutral' | 'brand' | 'success' | 'warn' | 'danger' | 'violet''neutral'Badge color. Its type is AccentTone.
defaultExpanded boolean no defaultOpen on first render.
match 'exact' | 'prefix' | 'none' no defaultHow activePath matches. Defaults to 'exact' for a leaf and 'prefix' for a node with children.
disabled booleanfalseRender the row as text rather than a link, so it is neither clickable nor focusable.