Tabs
A tabbed interface component with 3 visual variants, animated indicator, and vertical orientation support.
Basic
A tabbed navigation component for switching between content panels. Built on Radix UI with an animated active indicator powered by Framer Motion.
Installation
Install the component via the CLI in one command.
npx @work-rjkashyap/unified-ui add tabspnpm dlx @work-rjkashyap/unified-ui add tabsnpx @work-rjkashyap/unified-ui add tabsbunx @work-rjkashyap/unified-ui add tabsIf you haven't initialized your project yet, run npx @work-rjkashyap/unified-ui init first. See the CLI docs for
details.
Or install the full package
Use this approach if you prefer to install the entire design system as a dependency instead of copying individual components.
npm install @work-rjkashyap/unified-uipnpm add @work-rjkashyap/unified-uiyarn add @work-rjkashyap/unified-uibun add @work-rjkashyap/unified-uiAnatomy
import {
Tabs,
TabsList,
TabsTrigger,
TabsContent,
} from "@work-rjkashyap/unified-ui";Basic Usage
The Tabs component wraps Radix UI's Tabs primitive with design system tokens and an animated active indicator powered by Framer Motion's layoutId.
Variants
Three visual variants are available to suit different UI contexts.
Underline (default)
The standard tab style with a bottom border indicator. Best for top-level page navigation.
Pills
Rounded pill-shaped buttons for the active tab. Great for filtering or secondary navigation.
Enclosed
Tabs enclosed in a container with a background highlight on the active tab. Works well in card headers and toolbars.
Sizes
Two sizes are available for different density requirements.
Small
Medium (default)
Vertical Orientation
Set orientation="vertical" for a sidebar-style layout where the tab list sits on the left and content on the right.
Full Width
Set fullWidth on the TabsList to stretch tabs evenly across the available width.
Disabled Tabs
Individual tabs can be disabled while others remain interactive.
Controlled
Use value and onValueChange for controlled tab state.
const [activeTab, setActiveTab] = useState("overview");
<Tabs value={activeTab} onValueChange={setActiveTab}>
<TabsList>
<TabsTrigger value="overview">Overview</TabsTrigger>
<TabsTrigger value="details">Details</TabsTrigger>
</TabsList>
<TabsContent value="overview">Overview content</TabsContent>
<TabsContent value="details">Details content</TabsContent>
</Tabs>;Animated Indicator
The active tab indicator uses Framer Motion's layoutId for smooth animated transitions between tabs. The animation automatically respects prefers-reduced-motion via the useReducedMotion hook — when the user prefers reduced motion, the indicator snaps instantly without animation.
Props
Tabs
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "underline" | "pills" | "enclosed" | "underline" | Visual variant of the tabs. |
size | "sm" | "md" | "md" | Size of the tab triggers. |
orientation | "horizontal" | "vertical" | "horizontal" | Layout direction. |
value | string | — | Controlled active tab value. |
defaultValue | string | — | Default active tab (uncontrolled). |
onValueChange | (value: string) => void | — | Callback when the active tab changes. |
className | string | — | Additional CSS classes. |
TabsList
| Prop | Type | Default | Description |
|---|---|---|---|
fullWidth | boolean | false | Stretch tabs to fill available width. |
className | string | — | Additional CSS classes. |
TabsTrigger
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | required | The value identifying this tab. |
disabled | boolean | false | Disables this tab trigger. |
className | string | — | Additional CSS classes. |
TabsContent
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | required | The value identifying this content panel. |
forceMount | boolean | false | Force mount the content even when inactive. |
className | string | — | Additional CSS classes. |
Accessibility
Built on @radix-ui/react-tabs which provides full keyboard navigation and ARIA attributes out of the box.
- Arrow keys — Navigate between tab triggers (left/right for horizontal, up/down for vertical).
- Home/End — Jump to the first or last tab.
- Enter/Space — Activate the focused tab (automatic activation by default).
- The tab list renders with
role="tablist"and each trigger hasrole="tab". - Content panels have
role="tabpanel"and are linked to their trigger viaaria-labelledby. aria-selectedis set on the active tab trigger.aria-orientationis set on the tab list whenorientationis specified.- Disabled tabs are removed from the tab order and marked with
aria-disabled. - Focus ring is visible on keyboard navigation only (
focus-visible). - The animated indicator respects
prefers-reduced-motionviauseReducedMotion.
Design Tokens
| Token | Usage |
|---|---|
--primary | Active tab indicator / highlight |
--muted | Inactive tab background (enclosed/pills) |
--foreground | Active tab text color |
--muted-foreground | Inactive tab text color |
--radius-md | Tab trigger border radius |
--duration-fast | Transition speed for hover/focus states |