KQ-1171 · RIBBON/TABS
Ribbon Tabs
Tabs drawn as lengths of fabric hanging from a rail: the chosen ribbon drops further on a spring set by the cloth and its colour deepens on a tween, while every ribbon is a pendulum that the change of tab tugs into a swing, the new one hardest, with a wave of smaller kicks running along the rail and each tail lagging so the cloth bends. The panel below cross-fades in the direction of travel and its height glides; brushing the pointer across the ribbons sets them swinging, and a ribbon pulled down like a cord follows the hand 1:1 and is chosen past half its drop. It is a real tablist: arrow keys move and choose with the same sway, Home and End jump.
$2,418.60out
Groceries and transit lead.
Spend · 1 of 4 · $2,418.60 out
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/ribbon-tabs
Props
- tabs
- { id: string; label: string; content: ReactNode; disabled?: boolean }[]
- default —
- The ribbons, left to right, and what each one's panel shows.
- value / defaultValue
- string
- default the first enabled tab
- The chosen tab's id, controlled or initial.
- onValueChange
- (id: string) => void
- default —
- Fires from the tap, tug or key that chose a tab, with its id.
- label
- string
- default —
- The tab list's accessible name.
- sway
- number
- default 0.5
- How freely the ribbons swing, 0 to 1: 0 hangs rigid, 1 swings long and lazily.
- fabric
- "satin" | "linen" | "velvet"
- default "satin"
- The cloth: glossy satin with a swallowtail, matte linen with a stitched hem, or heavy velvet with a pointed end. Sets the look, the cut and the weight of the swing.
- length
- number
- default 40
- How much further the chosen ribbon drops than the rest, in px (24 to 64).
- color
- string
- default "var(--accent)"
- The fabric's colour, any CSS colour; the pale and deep shades are drawn from it at fixed lightness.
- sound
- boolean
- default false
- Play a swish when the visitor changes tab, and a soft one when a fast brush crosses a ribbon.
- disabled
- boolean
- default false
- Every ribbon can be read but not chosen, tugged or brushed.
- className
- string
- default —
- Classes for the root, which holds the rail and the panel.
| Prop | Type | Default | Description |
|---|---|---|---|
| tabs | { id: string; label: string; content: ReactNode; disabled?: boolean }[] | — | The ribbons, left to right, and what each one's panel shows. |
| value / defaultValue | string | the first enabled tab | The chosen tab's id, controlled or initial. |
| onValueChange | (id: string) => void | — | Fires from the tap, tug or key that chose a tab, with its id. |
| label | string | — | The tab list's accessible name. |
| sway | number | 0.5 | How freely the ribbons swing, 0 to 1: 0 hangs rigid, 1 swings long and lazily. |
| fabric | "satin" | "linen" | "velvet" | "satin" | The cloth: glossy satin with a swallowtail, matte linen with a stitched hem, or heavy velvet with a pointed end. Sets the look, the cut and the weight of the swing. |
| length | number | 40 | How much further the chosen ribbon drops than the rest, in px (24 to 64). |
| color | string | "var(--accent)" | The fabric's colour, any CSS colour; the pale and deep shades are drawn from it at fixed lightness. |
| sound | boolean | false | Play a swish when the visitor changes tab, and a soft one when a fast brush crosses a ribbon. |
| disabled | boolean | false | Every ribbon can be read but not chosen, tugged or brushed. |
| className | string | — | Classes for the root, which holds the rail and the panel. |