KQ-1172 · CABINET/MENU
Cabinet Menu
A nested menu drawn as a filing cabinet: each top item is a drawer that slides out toward you on its runners, the front coming down and growing a hair nearer while the inside is revealed above it with walls, runners and hanging folders, and at depth 3 a folder opens on the glide spring to fan out its sheets. The slide is one spring per drawer set by runners, from wooden slides that stop dead to ball-bearing slides that bump the end-stop and rebound when shut hard, with a thock timed to the stop; the pull follows the hand 1:1 and a throw is projected open or shut. It is a vertical menubar: Up and Down walk a level, Right, Enter or Space open and step in, and Left or Escape push the innermost drawer or folder home one at a time.
4 drawers · pull one
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/cabinet-menu
Props
- drawers
- { id: string; label: string; folders: { id: string; label: string; items?: { id: string; label: string; meta?: string }[] }[] }[]
- default —
- The cabinet, top drawer first: each drawer's folders and each folder's sheets.
- value / defaultValue
- string | null
- default null
- The chosen leaf's id (a sheet, or a folder that is a leaf), controlled or initial.
- onValueChange
- (id: string, path: string[]) => void
- default —
- Fires from the press or key that chose a leaf, with its id and the labels from drawer to leaf.
- onOpenChange
- (drawerId: string | null) => void
- default —
- Fires when a drawer comes out, with its id, or when every drawer is home, with null.
- label
- string
- default —
- The menu's accessible name.
- depth
- number
- default 3
- How many levels the menu has: 2 (drawers, folders as leaves) or 3 (drawers, folders, sheets).
- runners
- number
- default 0.6
- The runners, 0 to 1: plain wooden slides that stop dead, up to ball-bearing slides that glide, bump the end-stop and rebound when shut hard. Also changes the runner hardware drawn.
- finish
- "steel" | "oak" | "mint"
- default "steel"
- The cabinet's material: brushed steel with chrome pulls, oak with grain and brass pulls, or mint enamel.
- sound
- boolean
- default false
- Play a thock when a drawer the visitor moved meets its stop, and paper as folders open and a leaf is chosen.
- disabled
- boolean
- default false
- The cabinet can be read but no drawer opens.
- className
- string
- default —
- Classes for the cabinet's carcass.
| Prop | Type | Default | Description |
|---|---|---|---|
| drawers | { id: string; label: string; folders: { id: string; label: string; items?: { id: string; label: string; meta?: string }[] }[] }[] | — | The cabinet, top drawer first: each drawer's folders and each folder's sheets. |
| value / defaultValue | string | null | null | The chosen leaf's id (a sheet, or a folder that is a leaf), controlled or initial. |
| onValueChange | (id: string, path: string[]) => void | — | Fires from the press or key that chose a leaf, with its id and the labels from drawer to leaf. |
| onOpenChange | (drawerId: string | null) => void | — | Fires when a drawer comes out, with its id, or when every drawer is home, with null. |
| label | string | — | The menu's accessible name. |
| depth | number | 3 | How many levels the menu has: 2 (drawers, folders as leaves) or 3 (drawers, folders, sheets). |
| runners | number | 0.6 | The runners, 0 to 1: plain wooden slides that stop dead, up to ball-bearing slides that glide, bump the end-stop and rebound when shut hard. Also changes the runner hardware drawn. |
| finish | "steel" | "oak" | "mint" | "steel" | The cabinet's material: brushed steel with chrome pulls, oak with grain and brass pulls, or mint enamel. |
| sound | boolean | false | Play a thock when a drawer the visitor moved meets its stop, and paper as folders open and a leaf is chosen. |
| disabled | boolean | false | The cabinet can be read but no drawer opens. |
| className | string | — | Classes for the cabinet's carcass. |