Skip to content
Docs

Tabs

A set of layered sections of content—known as tab panels—that are displayed one at a time.

A set of layered sections of content—known as tab panels—that are displayed one at a time.

Make changes to your account here. Click save when you're done.

<Tabs.root
  id="tabs-primitive"
  class="DemoTabsRoot"
  default_value="tab1"
>
  <Tabs.list
    class="DemoTabsList"
    aria-label="Manage your account"
  >
    <Tabs.trigger
      class="DemoTabsTrigger"
      value="tab1"
    >
      Account
    </Tabs.trigger>
    <Tabs.trigger
      class="DemoTabsTrigger"
      value="tab2"
    >
      Password
    </Tabs.trigger>
  </Tabs.list>
  <Tabs.content
    class="DemoTabsContent"
    value="tab1"
  >
    <p class="DemoText">
      Make changes to your account here. Click save when you're done.
    </p>
    <fieldset class="DemoFieldset">
      <label
        class="DemoLabel"
        for="name"
      >
        Name
      </label>
      <input
        class="DemoInput"
        id="name"
        value="Pedro Duarte"
      />
    </fieldset>
    <fieldset class="DemoFieldset">
      <label
        class="DemoLabel"
        for="username"
      >
        Username
      </label>
      <input
        class="DemoInput"
        id="username"
        value="@peduarte"
      />
    </fieldset>
    <div style="display: flex; margin-top: 20px; justify-content: flex-end;">
      <button class="DemoButton green">Save changes</button>
    </div>
  </Tabs.content>
  <Tabs.content
    class="DemoTabsContent"
    value="tab2"
  >
    <p class="DemoText">
      Change your password here. After saving, you'll be logged out.
    </p>
    <fieldset class="DemoFieldset">
      <label
        class="DemoLabel"
        for="currentPassword"
      >
        Current password
      </label>
      <input
        class="DemoInput"
        id="currentPassword"
        type="password"
      />
    </fieldset>
    <fieldset class="DemoFieldset">
      <label
        class="DemoLabel"
        for="newPassword"
      >
        New password
      </label>
      <input
        class="DemoInput"
        id="newPassword"
        type="password"
      />
    </fieldset>
    <fieldset class="DemoFieldset">
      <label
        class="DemoLabel"
        for="confirmPassword"
      >
        Confirm password
      </label>
      <input
        class="DemoInput"
        id="confirmPassword"
        type="password"
      />
    </fieldset>
    <div style="display: flex; margin-top: 20px; justify-content: flex-end;">
      <button class="DemoButton green">Change password</button>
    </div>
  </Tabs.content>
</Tabs.root>
Can be controlled or uncontrolled.
Supports horizontal/vertical orientation.
Supports automatic/manual activation.
Full keyboard navigation.

Anatomy

Import all parts and piece them together.

<Tabs.root>
  <Tabs.list>
    <Tabs.trigger />
  </Tabs.list>
  <Tabs.content />
</Tabs.root>

Anatomy

Root
Contains all the tabs component parts.
List
Contains the triggers that are aligned along the edge of the active content.
Trigger
The button that activates its associated content.
Content
Contains the content associated with each trigger.

API Reference

Root

Contains all the tabs component parts.

Use value with on_value_change for controlled tab state in LiveView:

<Tabs.root id="account-tabs" value={@tab} on_value_change="tabs_value_change">
  …
</Tabs.root>
def handle_event("tabs_value_change", %{"value" => value}, socket) do
  {:noreply, assign(socket, :tab, value)}
end
Prop Type Default Description
activation_mode string "automatic"
default_value string nil
dir string "ltr"
id string
on_value_change string nil
orientation string "horizontal"
value string nil
activation_mode
Type string Default "automatic"
default_value
Type string Default nil
dir
Type string Default "ltr"
id
Type string Default
on_value_change
Type string Default nil
orientation
Type string Default "horizontal"
value
Type string Default nil

Data attributes

Attribute Values Description
[data-orientation] vertical | horizontal The orientation of the component.

List

Contains the triggers that are aligned along the edge of the active content.

Prop Type Default Description
loop boolean true
orientation string "horizontal"
loop
Type boolean Default true
orientation
Type string Default "horizontal"

Data attributes

Attribute Values Description
[data-orientation] vertical | horizontal The orientation of the component.

Trigger

The button that activates its associated content.

Prop Type Default Description
disabled boolean false
id string nil
orientation string "horizontal"
value string
disabled
Type boolean Default false
id
Type string Default nil
orientation
Type string Default "horizontal"
value
Type string Default

Data attributes

Attribute Values Description
[data-state] active | inactive Reflects whether the tab is active.
[data-disabled] Present when disabled Present when the tab is disabled.
[data-orientation] vertical | horizontal The orientation of the component.

Content

Contains the content associated with each trigger.

Prop Type Default Description
force_mount boolean false
id string nil
orientation string "horizontal"
value string
force_mount
Type boolean Default false
id
Type string Default nil
orientation
Type string Default "horizontal"
value
Type string Default

Data attributes

Attribute Values Description
[data-state] active | inactive Reflects whether the tab is active.
[data-orientation] vertical | horizontal The orientation of the component.

Examples

Vertical

You can create vertical tabs by using the orientation prop.

<Tabs.root id="tabs-vertical" default_value="tab1" orientation="vertical" class="DemoTabsRoot DemoTabsRootVertical">
  <Tabs.list aria-label="Tabs example" class="DemoTabsList DemoTabsListVertical">
    <Tabs.trigger value="tab1" class="DemoTabsTrigger">One</Tabs.trigger>
    <Tabs.trigger value="tab2" class="DemoTabsTrigger">Two</Tabs.trigger>
    <Tabs.trigger value="tab3" class="DemoTabsTrigger">Three</Tabs.trigger>
  </Tabs.list>
  <Tabs.content value="tab1" class="DemoTabsContent">Tab one content</Tabs.content>
  <Tabs.content value="tab2" class="DemoTabsContent">Tab two content</Tabs.content>
  <Tabs.content value="tab3" class="DemoTabsContent">Tab three content</Tabs.content>
</Tabs.root>
.DemoTabsRootVertical {
  flex-direction: row;
}
.DemoTabsListVertical {
  flex-direction: column;
  border-bottom: none;
  border-right: 1px solid var(--mauve-6);
}
.DemoTabsRootVertical .DemoTabsTrigger:first-child {
  border-top-left-radius: 6px;
  border-top-right-radius: 0;
}
.DemoTabsRootVertical .DemoTabsTrigger:last-child {
  border-top-right-radius: 0;
}
.DemoTabsRootVertical .DemoTabsContent {
  border-bottom-left-radius: 0;
  border-top-right-radius: 6px;
}

Accessibility

Adheres to the Tabs WAI-ARIA design pattern.

Keyboard Interactions

Keyboard Interactions

Key Description
Tab When focus moves onto the tabs, focuses the active trigger. When a trigger is focused, moves focus to the active content.
ArrowDown Moves focus to the next trigger depending on `orientation` and activates its associated content.
ArrowRight Moves focus to the next trigger depending on `orientation` and activates its associated content.
ArrowUp Moves focus to the previous trigger depending on `orientation` and activates its associated content.
ArrowLeft Moves focus to the previous trigger depending on `orientation` and activates its associated content.
Home Moves focus to the first trigger and activates its associated content.
End Moves focus to the last trigger and activates its associated content.