Liquid tab barPro
Tabs with a liquid selection that stretches between them and fills in icons as it passes.
Live · keyboard ready
- Switching between a handful of peer sections with icons, such as an app's main areas.
- Bottom or top bars on mobile-style layouts where the selection should feel physical.
- Tabs that carry badge counts for new items.
- Use tabs for text-only panels inside a page.
- Use segmented-control for compact filters or view toggles.
- Use morph-nav for site navigation with dropdown panels.
Installation
Pro source and install commands unlock with a Pro plan.
example.tsx
import { LiquidTabBar, liquidPanelId, liquidTabId } from "@/registry/components/liquid-tab-bar/liquid-tab-bar";import { Home, Library, Radio } from "lucide-react"; export function Sections() { const [tab, setTab] = useState("home"); return ( <> <LiquidTabBar id="nav" value={tab} onValueChange={setTab} tabs={[ { value: "home", label: "Home", icon: <Home /> }, { value: "radio", label: "Radio", icon: <Radio />, badge: 2, badgeLabel: "2 new" }, { value: "library", label: "Library", icon: <Library /> }, ]} /> <section id={liquidPanelId("nav", tab)} role="tabpanel" aria-labelledby={liquidTabId("nav", tab)}>{/* ... */}</section> </> );}API reference
2 parts. The first is the root.
LiquidTabBar
Horizontal navigation for a handful of peer sections. The selection is a liquid lens that stretches toward the new tab and redraws what passes under it inverted, so outline icons fill in.
PropTypeDefaultDescription
tabsRequired{ value: string; label: string; icon: ReactNode; activeIcon?: ReactNode; badge?: number; badgeLabel?: string }[]–Tabs in order. activeIcon is drawn inside the lens (defaults to icon filled in); badge is a rolling count and badgeLabel what screen readers hear with it.valueRequiredstring–Selected tab value.onValueChangeRequired(value: string) => void–Called when a tab is chosen by tap, drag, or keyboard.labels"active" | "always" | "none""active"Which tabs show their label: the selected one, every tab, or none.labelstring"Sections"Accessible name of the tab list.idstring–Base id for tab and panel ids. Defaults to a generated id.classNamestring–Extra class on the tab list.liquidTabId / liquidPanelId
Helpers that return a tab's id and the panel id its aria-controls points at, so panels can be wired up.
PropTypeDefaultDescription
idRequiredstring–The base id passed to LiquidTabBar.valueRequiredstring–The tab value.- ArrowLeftorArrowRight
- Selects the previous or next tab and moves focus to it, wrapping at the ends.
- HomeorEnd
- Selects the first or last tab.
- Uses the tablist and tab roles with aria-selected, aria-controls, and a roving tabindex.
- Each tab's accessible name includes its badge, using badgeLabel when given.
- The inverted copy inside the lens is decorative; only one set of tabs is exposed.
- The lens's leading edge races to the new tab while the trailing edge catches up, so it stretches with distance and speed and thins as it stretches; it leans toward a hovered tab.
- Grab the lens on the selected tab and drag or throw it; it lands where its momentum reaches, a quick flick always moves at least one tab, and it resists past either end. The selected tab's label opens on a spring and badge digits roll.
- Reduced motion jumps the lens and labels to their places without stretch or lean.
- Slots are a fixed 44px plus the open label, and the bar caps at max-width 100%; set labels to none when space is tight.
- The bar uses touch-action pan-y, so dragging the lens sideways works on touch without blocking page scroll.
- Hover lean follows the mouse only; touch selects on tap or throw.
- The lens animates a clip-path over an inverted copy of the tabs, so every tab is rendered twice.
- Label widths are measured from hidden copies whenever tabs change; keep the tab count to a handful.
Notes for AI
Give your coding assistant the Markdown reference instead of screenshots.
- Choose it for switching between a handful of peer sections with icons, such as an app's main areas. Use tabs for text-only in-page panels and segmented-control for compact filters.
- It is controlled: keep value in state. Wire panels with liquidPanelId and liquidTabId using the same id prop.
The full library index for assistants is at /llms.txt.
