Glide tabs
Tabs with a pill that glides under the active label.
Behaviour
- Reduced motion: the pill moves instantly.
- A pill glides under the active label on one spring, and picking another tab mid-glide carries on from where it is.
- Arrow keys, Home and End move between enabled tabs, with one tab stop (roving tabindex).
- It renders the tab bar only: show your own panel for the selected value.
- A long list scrolls inside its own rounded bar rather than breaking the page.
Props
| Prop | Type | Description |
|---|---|---|
| tabs | (string | { value, label, disabled? })[] | The tabs, in order. A string is both label and value. Values must be unique. |
| value | string | Controlled value. Leave it out and the tabs keep their own state. |
| defaultValue | string | Starting tab when uncontrolled. Defaults to the first. |
| onValueChange | (value: string) => void | Called when another tab is picked. |
| label | stringdefault "Tabs" | Accessible name for the tab list. |
| orientation | "horizontal" | "vertical"default "horizontal" | Vertical stacks the tabs and uses the up and down arrows. |
| idPrefix | string | Wires your panels: tab ids are ${idPrefix}-tab-${value} and point at ${idPrefix}-panel-${value}. |
| className | string | Size comes from here, e.g. text-lg. Merged with cn(). |
Installation
npx shadcn@latest add https://purrfectui.com/r/glide-tabs.jsonHow to use
import { GlideTabs } from "@/components/ui/glide-tabs";
const [tab, setTab] = useState("preview");
<GlideTabs
tabs={[{ value: "preview", label: "Preview" }, { value: "code", label: "Code" }, { value: "docs", label: "Docs", disabled: true }]}
value={tab}
onValueChange={setTab}
idPrefix="demo"
/>
<div role="tabpanel" id={`demo-panel-${tab}`} aria-labelledby={`demo-tab-${tab}`}>…</div>Source code
Loading…
License
MIT. Copy it into your project and change it as you like.