Skip to main content

Tabs

Tabs are navigation controls for switching between related views, like a project's overview, activity, and settings. They show one panel at a time and can also work as a single-choice form field.

Import

import { Tabs } from '@vortexlabs/vortex';
import type { TabsProps } from '@vortexlabs/vortex';

Other links

Project summary and current status.
<Tabs
  variant="underline"
  size="md"
  defaultValue="overview"
>
  <Stack gap={4} width="320px" maxWidth="100%">
  <Tabs.List>
    <Tabs.Item value="overview">Overview</Tabs.Item>
    <Tabs.Item value="activity">Activity</Tabs.Item>
    <Tabs.Item value="settings">Settings</Tabs.Item>
  </Tabs.List>
  <Tabs.Panel value="overview">Project summary and current status.</Tabs.Panel>
  <Tabs.Panel value="activity">Recent changes to the project.</Tabs.Panel>
  <Tabs.Panel value="settings">Members, permissions, and integrations.</Tabs.Panel>
</Stack>
</Tabs>

Features

  • Pairs each tab with a panel by value.
  • Supports three variants and three sizes.
  • Supports vertical lists and equal-width items.
  • Can contain text, icon, or endSlot.
  • Supports disabled items and controlled selection.
  • Works as a form field with name, using native radio inputs.
Reference Links
WAI-ARIA tabs pattern

Anatomy

Tabs holds the selection, List holds the tabs, each Item is one tab, and each Panel shows the content for the item with the matching value.

<Tabs>
  <Tabs.List>
    <Tabs.Item value="overview">Overview</Tabs.Item>
    <Tabs.Item value="activity">Activity</Tabs.Item>
  </Tabs.List>
  <Tabs.Panel value="overview">Project summary and current status.</Tabs.Panel>
  <Tabs.Panel value="activity">Recent changes to the project.</Tabs.Panel>
</Tabs>

Variants

The default underline variant marks the selected tab with a line. pill highlights it with a background, and segment places the tabs on a track, like a segmented control.

<Tabs variant="underline" defaultValue="overview">
  <Tabs.List>
    <Tabs.Item value="overview">Overview</Tabs.Item>
    <Tabs.Item value="activity">Activity</Tabs.Item>
  </Tabs.List>
</Tabs>
<Tabs variant="pill" defaultValue="overview">
  <Tabs.List>
    <Tabs.Item value="overview">Overview</Tabs.Item>
    <Tabs.Item value="activity">Activity</Tabs.Item>
  </Tabs.List>
</Tabs>
<Tabs variant="segment" defaultValue="overview">
  <Tabs.List>
    <Tabs.Item value="overview">Overview</Tabs.Item>
    <Tabs.Item value="activity">Activity</Tabs.Item>
  </Tabs.List>
</Tabs>

Color

On the underline variant, color="primary" colors the selection indicator.

<Tabs color="primary" defaultValue="overview">
  <Tabs.List>
    <Tabs.Item value="overview">Overview</Tabs.Item>
    <Tabs.Item value="activity">Activity</Tabs.Item>
  </Tabs.List>
</Tabs>

Sizes

Tabs come in three sizes: sm, md, and lg. The default is md.

<Tabs size="sm" defaultValue="preview">
  <Tabs.List>
    <Tabs.Item value="preview">Preview</Tabs.Item>
    <Tabs.Item value="code">Code</Tabs.Item>
  </Tabs.List>
</Tabs>
<Tabs size="md" defaultValue="preview">
  <Tabs.List>
    <Tabs.Item value="preview">Preview</Tabs.Item>
    <Tabs.Item value="code">Code</Tabs.Item>
  </Tabs.List>
</Tabs>
<Tabs size="lg" defaultValue="preview">
  <Tabs.List>
    <Tabs.Item value="preview">Preview</Tabs.Item>
    <Tabs.Item value="code">Code</Tabs.Item>
  </Tabs.List>
</Tabs>

Equal Widths

Set equalWidthItems to give every tab the same width.

Projects being prepared.
<Tabs variant="segment" equalWidthItems defaultValue="draft">
  <Tabs.List>
    <Tabs.Item value="draft">Draft</Tabs.Item>
    <Tabs.Item value="review">In review</Tabs.Item>
    <Tabs.Item value="published">Published</Tabs.Item>
  </Tabs.List>
  <Tabs.Panel value="draft">Projects being prepared.</Tabs.Panel>
  <Tabs.Panel value="review">Projects awaiting approval.</Tabs.Panel>
  <Tabs.Panel value="published">Projects available to your team.</Tabs.Panel>
</Tabs>

Vertical Tabs

Set orientation="vertical" to stack the tabs; only the underline variant supports it. Tabs has no built-in layout, so arrange the list and panels with Stack.

Update your name and profile details.
<Tabs orientation="vertical" defaultValue="profile">
  <Stack direction="row" gap={6}>
    <Tabs.List>
      <Tabs.Item value="profile">Profile</Tabs.Item>
      <Tabs.Item value="security">Security</Tabs.Item>
    </Tabs.List>
    <Tabs.Panel value="profile">Update your name and profile details.</Tabs.Panel>
    <Tabs.Panel value="security">Manage passwords and active sessions.</Tabs.Panel>
  </Stack>
</Tabs>

Icons

Add icon to show an icon before the label. Icon-only items need ariaLabel instead of children.

Preview the current document.
import { Eye, Heart } from "@vortexlabs/vortex-icons";

<Tabs variant="pill" defaultValue="preview">
  <Tabs.List>
    <Tabs.Item value="preview" icon={<Eye />}>Preview</Tabs.Item>
    <Tabs.Item value="favorites" icon={<Heart />} ariaLabel="Favorites" />
  </Tabs.List>
  <Tabs.Panel value="preview">Preview the current document.</Tabs.Panel>
  <Tabs.Panel value="favorites">Your favorite documents.</Tabs.Panel>
</Tabs>

End Slots

On Tabs.Item, endSlot shows a count or badge after the label; keep it non-interactive. On Tabs.List, it pins an action to the end of a horizontal list, outside the scroll area.

import { Badge, Button, Tabs } from "@vortexlabs/vortex";

<Tabs defaultValue="all">
  <Tabs.List endSlot={<Button size="sm" variant="secondary">New task</Button>}>
    <Tabs.Item value="all" endSlot={<Badge size="sm" rounded>24</Badge>}>
      All
    </Tabs.Item>
    <Tabs.Item value="open" endSlot={<Badge size="sm" rounded>3</Badge>}>
      Open
    </Tabs.Item>
  </Tabs.List>
</Tabs>

Disabled Items

Set disabled on an item to prevent selecting it; keyboard navigation skips it.

<Tabs defaultValue="overview">
  <Tabs.List>
    <Tabs.Item value="overview">Overview</Tabs.Item>
    <Tabs.Item value="reports" disabled>Reports</Tabs.Item>
    <Tabs.Item value="activity">Activity</Tabs.Item>
  </Tabs.List>
</Tabs>

Controlled Selection

The first enabled item is selected by default; set defaultValue when items render through custom components or load later. Pass value and update it in onChange. Inactive panels unmount their content, so keep state that must persist outside the panels.

Edit the project details.
"use client";

import { Button, Stack, Tabs } from "@vortexlabs/vortex";
import { useState } from "react";

export const TabsControlledExample = () => {
  const [value, setValue] = useState("details");

  return (
    <Stack gap={4}>
      <Tabs value={value} onChange={({ value }) => setValue(value)}>
        <Tabs.List>
          <Tabs.Item value="details">Details</Tabs.Item>
          <Tabs.Item value="preview">Preview</Tabs.Item>
        </Tabs.List>
        <Tabs.Panel value="details">Edit the project details.</Tabs.Panel>
        <Tabs.Panel value="preview">Review the project before publishing.</Tabs.Panel>
      </Tabs>
      <Button variant="secondary" onClick={() => setValue("preview")}>
        Open preview
      </Button>
    </Stack>
  );
};

Form Selection

Set name to render items as native radio inputs that submit the selected value with the form. Use this for a single choice, inside a fieldset with a legend and without panels.

Billing interval
"use client";

import { Button, Stack, Tabs, Text } from "@vortexlabs/vortex";
import { useState } from "react";

export const TabsFormExample = () => {
  const [saved, setSaved] = useState<string | null>(null);

  return (
    <form
      onSubmit={(event) => {
        event.preventDefault();
        setSaved(String(new FormData(event.currentTarget).get("billing")));
      }}
    >
      <Stack gap={4}>
        <fieldset>
          <legend>Billing interval</legend>
          <Tabs name="billing" variant="segment" defaultValue="monthly">
            <Tabs.List>
              <Tabs.Item value="monthly">Monthly</Tabs.Item>
              <Tabs.Item value="yearly">Yearly</Tabs.Item>
            </Tabs.List>
          </Tabs>
        </fieldset>
        <Button attributes={{ type: "submit" }}>Save preference</Button>
        {saved && <Text size="body-sm-desktop">Saved: {saved}</Text>}
      </Stack>
    </form>
  );
};

Accessibility

Key
Description
Left arrowRight arrowUp arrowDown arrow
Moves focus between tabs without selecting them. With name, it selects them, like native radio buttons.
HomeEnd
Moves focus to the first or last tab.
EnterSpace
Selects the focused tab and shows its panel.
Provide ariaLabel for icon-only items.
Wrap tabs that use name in a fieldset with a legend.