Tabs
Switch between views with an indicator that slides to the active tab, as a segmented control or an underline, and lists that scroll when they overflow.
Overview
Visitors are up 12% this week, mostly from search.
pnpm dlx shadcn@latest add https://hextaui.com/r/tabs.jsonAdds the component, the HextaUI theme tokens and any HextaUI components it depends on.
Add the theme tokens to your global CSS, if you haven’t yet.
Install the dependencies.
pnpm add @base-ui/react class-variance-authority cnCopy and paste the following code into your project.
components/ui/tabs.tsx Update the import paths to match your project setup.
One indicator slides to the active tab and resizes to fit it, while the content switches instantly so frequent switching never waits on an animation. The indicator is placed before the page hydrates, so it never jumps in on load.
Underline
variant="line" on TabsList slides an underline instead of a pill.
Activity for this repository.
Many tabs
When tabs don't fit, the list scrolls sideways, fades the edges with more to see, and scrolls the active or focused tab into view.
Many tabs, segmented
The pill style scrolls the same way, keeping its track while the picked tab stays in view.
Icons and counts
Put icons and badges inside triggers.
Vertical
orientation="vertical" stacks the tabs; the underline moves to the side.
General
Name, avatar and language.
Disabled
Disabled tabs are skipped by the keyboard.
Controlled
Pass value and onValueChange. Changes from outside slide the indicator too.
Right to left
Tabs, arrow keys and the indicator follow the reading direction.
إعدادات الحساب.
| Key | Action |
|---|---|
| Tab | Moves into the list on the active tab, then into the panel. |
| ←→ | Moves between tabs, wrapping at the ends. ↑ and ↓ when vertical. |
| HomeEnd | Moves to the first or last tab. |
| EnterSpace | Opens the focused tab. Set activateOnFocus on TabsList to open tabs as focus moves. |
- The list is a
tablist; each trigger is atabthat controls itstabpanel. - Panels are focusable, so keyboard users can reach content that has no links or buttons.
- With reduced motion, the indicator jumps instead of sliding.
| Prop | Type | Default |
|---|---|---|
value | any | – |
defaultValue | any | 0 |
onValueChange | (value, details) => void | – |
orientation | "horizontal" | "vertical" | "horizontal" |
| Attribute | Description |
|---|---|
data-activation-direction | "left", "right", "up" or "down": where the new tab is relative to the old one. |
| Prop | Type | Default |
|---|---|---|
variant | "default" | "line" | "default" |
activateOnFocus | boolean | false |
loopFocus | boolean | true |
| Attribute | Description |
|---|---|
data-slot="tabs-indicator" | The sliding pill or underline. |
data-scrolled-start / data-scrolled-end | Present when the list can scroll that way. |
--active-tab-left / --active-tab-width | Position and size of the active tab, also -top and -height. |
| Prop | Type | Default |
|---|---|---|
value | any | – |
disabled | boolean | false |
render | ReactElement | (props, state) => ReactElement | <button> |
| Attribute | Description |
|---|---|
data-active | The open tab. |
data-disabled | The tab is disabled. |
| Prop | Type | Default |
|---|---|---|
value | any | – |
keepMountedKeep the panel in the DOM while hidden. | boolean | false |