Unified UI

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.

Manage your account settings and preferences.

Installation

Install the component via the CLI in one command.

npx @work-rjkashyap/unified-ui add tabs
pnpm dlx @work-rjkashyap/unified-ui add tabs
npx @work-rjkashyap/unified-ui add tabs
bunx @work-rjkashyap/unified-ui add tabs

If 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-ui
pnpm add @work-rjkashyap/unified-ui
yarn add @work-rjkashyap/unified-ui
bun add @work-rjkashyap/unified-ui

Anatomy

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.

Content 1

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.

Overview content

Pills

Rounded pill-shaped buttons for the active tab. Great for filtering or secondary navigation.

All items

Enclosed

Tabs enclosed in a container with a background highlight on the active tab. Works well in card headers and toolbars.

Code editor

Sizes

Two sizes are available for different density requirements.

Small

Small tab content

Medium (default)

Medium tab content

Vertical Orientation

Set orientation="vertical" for a sidebar-style layout where the tab list sits on the left and content on the right.

General settings

Full Width

Set fullWidth on the TabsList to stretch tabs evenly across the available width.

First tab content

Disabled Tabs

Individual tabs can be disabled while others remain interactive.

First tab content

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

PropTypeDefaultDescription
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.
valuestringControlled active tab value.
defaultValuestringDefault active tab (uncontrolled).
onValueChange(value: string) => voidCallback when the active tab changes.
classNamestringAdditional CSS classes.

TabsList

PropTypeDefaultDescription
fullWidthbooleanfalseStretch tabs to fill available width.
classNamestringAdditional CSS classes.

TabsTrigger

PropTypeDefaultDescription
valuestringrequiredThe value identifying this tab.
disabledbooleanfalseDisables this tab trigger.
classNamestringAdditional CSS classes.

TabsContent

PropTypeDefaultDescription
valuestringrequiredThe value identifying this content panel.
forceMountbooleanfalseForce mount the content even when inactive.
classNamestringAdditional 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 has role="tab".
  • Content panels have role="tabpanel" and are linked to their trigger via aria-labelledby.
  • aria-selected is set on the active tab trigger.
  • aria-orientation is set on the tab list when orientation is 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-motion via useReducedMotion.

Design Tokens

TokenUsage
--primaryActive tab indicator / highlight
--mutedInactive tab background (enclosed/pills)
--foregroundActive tab text color
--muted-foregroundInactive tab text color
--radius-mdTab trigger border radius
--duration-fastTransition speed for hover/focus states

On this page