A pill-shaped tab bar that expands into a floating panel, with Motion driving the shell, label, and content transitions. React component.
Made by AxylPill tab bar expanding into a floating focus, progression, ideas, activity, and profile panel.
Tune the shared spring and label reveal timing with props:
Control the open tab yourself:
| Prop | Type | Default |
|---|---|---|
tabs? | ExpandableTab[] | - |
selectedId? | string | null | - |
defaultSelectedId? | string | null | null |
onSelectedIdChange? | (id: string | null) => void | - |
springDuration? | number | 0.45 |
springBounce? | number | 0 |
labelDelay? | number | 0.08 |
tapScale? | number | 0.8 |
maxContentWidth? | string | "24rem" |
className? | string | - |
classNames? | ExpandableTabsClassNames | - |
Use Expandable Tabs for compact toolbars or headers where a full nav bar would take up too much space — a focus/progress/ideas/activity/profile cluster, a floating action bar, or a mobile-friendly nav that only needs to reveal detail on demand. Pass any tab set and panel content via the tabs prop.
Avoid it when tab content needs to stay visible alongside other content, or when users need to compare multiple tabs' content at once — use a standard tabbed panel instead.
Each trigger button gets a stable id, aria-expanded, and aria-controls pointing at its panel's id; the open panel has a matching id, role="region", and aria-labelledby pointing back at its trigger — the same disclosure pattern used by Accordion, since Expandable Tabs can have zero panels open at once (unlike classic ARIA tabs, which always keep exactly one panel visible). Only the active tab's panel is mounted at a time, so aria-controls references an id that doesn't exist in the DOM while collapsed — accepted practice for this pattern, since aria-expanded="false" already communicates the state.
Pressing Escape while a panel is open closes it and returns focus to its trigger button. Clicking outside the root also closes the open panel.
useReducedMotion() collapses the shell, pill-width, label-reveal, and content slide/fade transitions to instant when prefers-reduced-motion: reduce is set.
Inspired by beui.dev's Expandable Tabs. Reimplemented for Motion and React.
Accordion
An animated FAQ accordion with expandable panels, powered by Motion. A React component for shadcn/ui.
Inline Testimonials
A flowing quote stream where each avatar reveals its author on hover, with Motion fading and blurring the rest. React component.
Built by Axyl. A motion-first component registry for React.
Last updated: 9/14/2026
Help keep SoraLabs moving.
Every contribution helps us build and maintain open-source tools for the community.
Sponsor on GitHub