KQ-2111 · FLYOUT/DOCK
Flyout Dock
An admin rail whose sections fly their pages out in a panel beside it on springs.glide, with an intent delay that a move toward the panel keeps restarting, so a diagonal sweep from one section to its panel never switches section; while it waits the rail's indicator leans toward the section under the pointer and snaps across on springs.snap once the switch commits. Pinning docks the panel as a permanent second column: one glide spring drives a single value that the panel's inset, radius and shadow and the page's left edge all read, so the floating card settles into a flush column as the page makes room. The rail is one tab stop where Up and Down open each section, Right steps into its pages and Left comes back, P pins, Escape closes, and under 300px the flyouts become drill-in screens.
Up and Down move along the sections and open each one. Right moves into its pages, Left comes back, P pins the panel as a column, Escape closes it.
Menu
Menu · Drinks · flyout
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/flyout-dock
Props
- sections
- FlyoutSection[]
- default defaultFlyoutSections
- The rail's sections: { id, label, railLabel?, icon, pages: { id, label, icon?, badge?, summary?, rows? }[], status?: ready | loading | error, badge?, emptyTitle?, emptyHint? }.
- page / defaultPage
- string
- default the first page
- The current page, controlled or initial.
- onNavigate
- (pageId: string, sectionId: string) => void
- default —
- A page was chosen from the flyout, the pinned column or a drill-in screen.
- open / defaultOpen
- string | null
- default null
- The section whose pages are out, controlled or initial.
- onOpenChange
- (sectionId: string | null) => void
- default —
- Fires from the hover, focus, key or press that opened or closed a section.
- pinned / defaultPinned
- boolean
- default false
- The panel docked as a second column, controlled or initial.
- onPin
- (sectionId: string) => void
- default —
- The panel was pinned while showing this section.
- onUnpin
- (sectionId: string) => void
- default —
- The panel was unpinned.
- onRetry
- (sectionId: string) => void
- default —
- Retry was pressed on a section whose pages failed to load.
- flyoutWidth
- number
- default 208
- The panel's width in px, floating and pinned; a pinned column narrows so the page keeps at least 112px.
- intentDelay
- number
- default 140
- How long the pointer rests on a section before it switches, in ms; every move toward the open panel restarts the wait.
- closeDelay
- number
- default 320
- How long an unpinned flyout stays after the pointer leaves, in ms.
- accent
- "cobalt" | "plum" | "mint" | "ink" | string
- default "cobalt"
- Indicator, current page, badges and pin. A name or any CSS colour.
- brand
- { name: string; initials: string }
- default { name: "Coldbrook", initials: "Cb" }
- The product at the top of the rail and the drill-in screens.
- railLabels
- boolean
- default true
- Labels under the rail's icons.
- frameHeight
- number
- default 520
- The frame's height in px.
- title
- string
- default "Coldbrook admin"
- The navigation's accessible name.
- disabled
- boolean
- default false
- Read only: nothing opens, pins or navigates.
- className
- string
- default —
- Classes for the frame.
| Prop | Type | Default | Description |
|---|---|---|---|
| sections | FlyoutSection[] | defaultFlyoutSections | The rail's sections: { id, label, railLabel?, icon, pages: { id, label, icon?, badge?, summary?, rows? }[], status?: ready | loading | error, badge?, emptyTitle?, emptyHint? }. |
| page / defaultPage | string | the first page | The current page, controlled or initial. |
| onNavigate | (pageId: string, sectionId: string) => void | — | A page was chosen from the flyout, the pinned column or a drill-in screen. |
| open / defaultOpen | string | null | null | The section whose pages are out, controlled or initial. |
| onOpenChange | (sectionId: string | null) => void | — | Fires from the hover, focus, key or press that opened or closed a section. |
| pinned / defaultPinned | boolean | false | The panel docked as a second column, controlled or initial. |
| onPin | (sectionId: string) => void | — | The panel was pinned while showing this section. |
| onUnpin | (sectionId: string) => void | — | The panel was unpinned. |
| onRetry | (sectionId: string) => void | — | Retry was pressed on a section whose pages failed to load. |
| flyoutWidth | number | 208 | The panel's width in px, floating and pinned; a pinned column narrows so the page keeps at least 112px. |
| intentDelay | number | 140 | How long the pointer rests on a section before it switches, in ms; every move toward the open panel restarts the wait. |
| closeDelay | number | 320 | How long an unpinned flyout stays after the pointer leaves, in ms. |
| accent | "cobalt" | "plum" | "mint" | "ink" | string | "cobalt" | Indicator, current page, badges and pin. A name or any CSS colour. |
| brand | { name: string; initials: string } | { name: "Coldbrook", initials: "Cb" } | The product at the top of the rail and the drill-in screens. |
| railLabels | boolean | true | Labels under the rail's icons. |
| frameHeight | number | 520 | The frame's height in px. |
| title | string | "Coldbrook admin" | The navigation's accessible name. |
| disabled | boolean | false | Read only: nothing opens, pins or navigates. |
| className | string | — | Classes for the frame. |