KQ-1173 · CANTILEVER/MENU
Cantilever Menu
An actions menu drawn as a cantilever toolbox: opening lifts the trays up and outward on parallelogram arms, each tray staying level while it rides a true circular arc over the top and out into a staircase, and its tools stand up out of it as it clears the tray below. One spring per tray drives the arc, the arms and the tools; arms sets the linkage from one stiff unit to springy arms that stagger and bounce at their stops with a clack each, and closing folds the trays back from the bottom up until the latch clicks. Choosing a tool lifts it out on snap before the box shuts; arrow keys walk the tools and cross trays, Up and Down move between trays, and Escape hands focus back to the latch.
3 trays shut · press the latch
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/cantilever-menu
Props
- groups
- { id: string; label: string; actions: { id: string; label: string; icon?: ReactNode; shortcut?: string; tone?: "default" | "danger" }[] }[]
- default —
- One group per tray, top tray first, up to four actions each; groups beyond the trays share the box's own compartment.
- label
- string
- default —
- The menu's name: the latch's accessible name, shown on its plate while shut.
- onAction
- (id: string) => void
- default —
- A tool was chosen. Fires as it lifts out, before the box folds shut.
- open / defaultOpen
- boolean
- default false
- Whether the box is open, controlled or initial.
- onOpenChange
- (open: boolean) => void
- default —
- Fires from the press, pull or key that opened or shut the box.
- trays
- number
- default 3
- How many tiers of trays the box has, 1 to 3. With fewer tiers than groups, the rest sit in the box.
- arms
- number
- default 0.5
- How springy the linked arms are, 0 to 1: 0 moves the trays as one stout, stiff unit; 1 has slender arms that let each tray lag the one above and bounce at its stop.
- finish
- "red" | "steel" | "green"
- default "red"
- The paint: red enamel, bare steel or green.
- sound
- boolean
- default false
- Play a clack as each tray the visitor opened reaches its stop and as a tool lifts out, and a click when the latch catches.
- disabled
- boolean
- default false
- The box stays shut and the latch cannot be pressed.
- className
- string
- default —
- Classes for the root, which is as tall as the box's tallest pose and scales down below 300 px wide.
| Prop | Type | Default | Description |
|---|---|---|---|
| groups | { id: string; label: string; actions: { id: string; label: string; icon?: ReactNode; shortcut?: string; tone?: "default" | "danger" }[] }[] | — | One group per tray, top tray first, up to four actions each; groups beyond the trays share the box's own compartment. |
| label | string | — | The menu's name: the latch's accessible name, shown on its plate while shut. |
| onAction | (id: string) => void | — | A tool was chosen. Fires as it lifts out, before the box folds shut. |
| open / defaultOpen | boolean | false | Whether the box is open, controlled or initial. |
| onOpenChange | (open: boolean) => void | — | Fires from the press, pull or key that opened or shut the box. |
| trays | number | 3 | How many tiers of trays the box has, 1 to 3. With fewer tiers than groups, the rest sit in the box. |
| arms | number | 0.5 | How springy the linked arms are, 0 to 1: 0 moves the trays as one stout, stiff unit; 1 has slender arms that let each tray lag the one above and bounce at its stop. |
| finish | "red" | "steel" | "green" | "red" | The paint: red enamel, bare steel or green. |
| sound | boolean | false | Play a clack as each tray the visitor opened reaches its stop and as a tool lifts out, and a click when the latch catches. |
| disabled | boolean | false | The box stays shut and the latch cannot be pressed. |
| className | string | — | Classes for the root, which is as tall as the box's tallest pose and scales down below 300 px wide. |