Components/SidebarNav

SidebarNav

A vertical workspace navigation with search and grouped destinations.

VerifiedSince 0.3.9

Usage

Workspace Navigation

search-hint="/" makes / focus the search field; the tinted highlight follows the pointer.

Loading demo...

Best Practices

  • Pass icons as inline SVG through the item-icon slot; the component sets their size and stroke.
  • Past a dozen items, turn on search rather than adding more groups.
  • For remote search, pass filter="items => items" and swap items on update:query; otherwise the built-in match filters the results again.
  • Make searchHint either a single typeable character, which really binds, or a complete glyph such as ⌘K that you wire to focusSearch(). A half-hint like Ctrl is neither.
  • Reserve badges for counts that need follow-up; decorative numbers dilute the real ones.

API Reference

Props

PropTypeDefaultDescription
itemsSidebarNavItem[]-Navigation items.
groupsSidebarNavGroup[]-Group definitions; items matching no group lead the list without a header.
modelValuestring | number-Active item (v-model).
querystring-Search text (v-model:query).
workspaceSidebarNavWorkspace-Workspace details; omit to drop the switcher row.
workspaceLabelstring'Switch workspace'Accessible name of the switcher button.
searchPlaceholderstring-Search placeholder; omit to drop the search row.
searchLabelstring-Accessible name of the field; falls back to the placeholder.
searchHintstring-Shortcut glyph at the end of the search row, such as /; a single character also binds that key.
actionLabelstring-Primary action label; omit to drop the button.
filter(items, query) => items-Replaces the built-in match; pass items => items for remote results.
ariaLabelstring'Workspace'Accessible name of the <nav> landmark.
indicatorDurationnumber220Highlight speed in ms, time-scaling the glide springs; values under 100 play as 100.

Events

EventPayloadDescription
update:modelValueSidebarNavValueFires when the active item changes.
update:querystringFires when the search text changes.
selectSidebarNavItemFires when an item is activated; disabled items don't emit.
action-Fires when the primary action button is pressed.
itemActionSidebarNavItemFires when a row's trailing quick action is pressed.
workspaceClick-Fires when the workspace switcher is pressed.

Slots

NameDescription
workspaceReplaces the whole workspace switcher row.
item-iconReplaces an item's leading icon; scope is { item, active }.
footerAppended below the groups.

Exposed Methods

NameDescription
focusSearch()Focuses the search field, for hosts wiring their own shortcut.
refreshIndicator()Re-measures the highlight after a layout change the observers miss; it lands in place.

Types

NameDescription
SidebarNavItem{ value, label, group?, icon?, badge?, action?, disabled? }; icon is an icon class that the item-icon slot overrides, and a changed badge replays its pop-in.
SidebarNavGroup{ key, label }; pass label in normal case, CSS uppercases it.
SidebarNavWorkspace{ name, description?, initials? }; initials defaults to the first character of name.

Overview

  • The active row has aria-current="page"; disabled items are real disabled buttons and emit no select.
  • The highlight is a pointer, not the selection: it follows hover and keyboard focus and returns to the active row when the pointer leaves the list. Label weight and badges carry the selection.
  • The highlight travels only when its target changes; the first measurement and re-measures of the same row land in place, and under reduced motion it jumps without the fade.
  • Typing filters live (case-insensitive includes on label), and a group left empty collapses with its header.
  • A single-character searchHint binds a document keydown that focuses the search field; a multi-character one such as ⌘K renders only as a badge. The binding stands down when focus is in a text field, Meta / Ctrl / Alt is held, the event was already handled, or there is no search row.
  • The trailing quick action is a sibling <button> of the row button and stays visible on touch (hover: none); group headers label their lists through aria-labelledby.

Technologies

  • useIndicatorBox measures the highlight and the glide material of useJellyIndicator moves it. useIndicatorBox is exported with the component (import { useIndicatorBox } from '@talex-touch/tuffex') and returns top / left / width / height for reuse in horizontal segmented controls.
  • The shortcut listener lives on document; enable enableAutoUnmount(afterEach) in tests, or a wrapper left mounted keeps consuming keys.
  • Source: packages/tuffex/packages/components/src/sidebar-nav/. Adapted from Beautiful UI, © 2026 Shane Levine, MIT.
查看源码
packages/tuffex/packages/components/src/sidebar-nav/index.ts