SidebarNav
A vertical workspace navigation with search and grouped destinations.
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-iconslot; 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 swapitemsonupdate:query; otherwise the built-in match filters the results again. - Make
searchHinteither a single typeable character, which really binds, or a complete glyph such as⌘Kthat you wire tofocusSearch(). A half-hint likeCtrlis neither. - Reserve badges for counts that need follow-up; decorative numbers dilute the real ones.
API Reference
Props
| Prop | Type | Default | Description |
|---|---|---|---|
items | SidebarNavItem[] | - | Navigation items. |
groups | SidebarNavGroup[] | - | Group definitions; items matching no group lead the list without a header. |
modelValue | string | number | - | Active item (v-model). |
query | string | - | Search text (v-model:query). |
workspace | SidebarNavWorkspace | - | Workspace details; omit to drop the switcher row. |
workspaceLabel | string | 'Switch workspace' | Accessible name of the switcher button. |
searchPlaceholder | string | - | Search placeholder; omit to drop the search row. |
searchLabel | string | - | Accessible name of the field; falls back to the placeholder. |
searchHint | string | - | Shortcut glyph at the end of the search row, such as /; a single character also binds that key. |
actionLabel | string | - | Primary action label; omit to drop the button. |
filter | (items, query) => items | - | Replaces the built-in match; pass items => items for remote results. |
ariaLabel | string | 'Workspace' | Accessible name of the <nav> landmark. |
indicatorDuration | number | 220 | Highlight speed in ms, time-scaling the glide springs; values under 100 play as 100. |
Events
| Event | Payload | Description |
|---|---|---|
update:modelValue | SidebarNavValue | Fires when the active item changes. |
update:query | string | Fires when the search text changes. |
select | SidebarNavItem | Fires when an item is activated; disabled items don't emit. |
action | - | Fires when the primary action button is pressed. |
itemAction | SidebarNavItem | Fires when a row's trailing quick action is pressed. |
workspaceClick | - | Fires when the workspace switcher is pressed. |
Slots
| Name | Description |
|---|---|
workspace | Replaces the whole workspace switcher row. |
item-icon | Replaces an item's leading icon; scope is { item, active }. |
footer | Appended below the groups. |
Exposed Methods
| Name | Description |
|---|---|
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
| Name | Description |
|---|---|
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 realdisabledbuttons and emit noselect. - 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
includesonlabel), and a group left empty collapses with its header. - A single-character
searchHintbinds adocumentkeydown that focuses the search field; a multi-character one such as⌘Krenders 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 througharia-labelledby.
Technologies
useIndicatorBoxmeasures the highlight and the glide material ofuseJellyIndicatormoves it.useIndicatorBoxis exported with the component (import { useIndicatorBox } from '@talex-touch/tuffex') and returnstop / left / width / heightfor reuse in horizontal segmented controls.- The shortcut listener lives on
document; enableenableAutoUnmount(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