Sliding Tabs
Tab navigation with a sliding pill indicator built on Radix Tabs, with default and glass variants and a smooth measured animation.
Sliding Tabs
Default
Muted track with a primary-colored sliding pill. Hover a tab to preview the indicator before selecting.
Glass
Frosted glass variant for dark surfaces. Supports optional icons per tab.
Install
Requires a project with shadcn/ui initialized. Installs all 2 files and any listed registry dependencies.
npx shadcn@latest add https://manglekuo.com/showcase/r/sliding-tabs.json@ui/sliding-tabs.tsx@ui/sliding-tabs.css
npm deps: @radix-ui/react-tabs, class-variance-authority
Documentation
Sliding Tabs
Tab navigation with a sliding pill indicator built on Radix Tabs. Includes default and glass variants, plus convenience helpers for item-driven bars and panels.
How it works
A small hook measures the active (and hovered) trigger's geometry with getBoundingClientRect and writes it to CSS custom properties on the list. Two indicator elements animate transform, width, and height toward those values. Because the animated properties' computed values actually change, the transition fires reliably no matter how fast or in what order you switch tabs — a MutationObserver tracks Radix's data-state changes and a ResizeObserver keeps it aligned on layout changes.
Usage
Composable API
import { SlidingTabs, SlidingTabsList, SlidingTabsTrigger, SlidingTabsContent,} from '@/components/ui/sliding-tabs'; <SlidingTabs defaultValue="account"> <SlidingTabsList> <SlidingTabsTrigger value="account">Account</SlidingTabsTrigger> <SlidingTabsTrigger value="password">Password</SlidingTabsTrigger> </SlidingTabsList> <SlidingTabsContent value="account">Account panel</SlidingTabsContent> <SlidingTabsContent value="password">Password panel</SlidingTabsContent></SlidingTabs>Language: jsxItem-driven helpers
import { SlidingTabs, SlidingTabsBar, SlidingTabsContent, SlidingTabsPanel,} from '@/components/ui/sliding-tabs'; const tabs = [ { value: 'voice', label: 'Voice', icon: Mic }, { value: 'type', label: 'Type', icon: Keyboard },]; <SlidingTabs defaultValue="voice"> <SlidingTabsBar items={tabs} variant="glass" aria-label="Input method" /> {tabs.map(({ value }) => ( <SlidingTabsContent key={value} value={value}> <SlidingTabsPanel>Panel content</SlidingTabsPanel> </SlidingTabsContent> ))}</SlidingTabs>Language: jsxProps
SlidingTabsBar
items(SlidingTabItem[]): Tab definitions withvalue,label, optionalicon, anddisabled.variant("default"|"glass"): Visual style of the tab bar.listClassName/triggerClassName: Extra classes for the list or triggers.disabled: Disables all tabs whentrue.aria-label: Accessible label for the tab list.
Variants
default: Muted rounded track with a primary-colored pill. Best on standard surfaces.glass: Frosted glass pill on dark or image backgrounds. Usesbackdrop-blurand translucent borders.
CSS
The component ships sliding-tabs.css with the .sliding-pill utilities. It is imported automatically from sliding-tabs.tsx, so no extra setup is required.