Skip to content
Componentsbeta

Tabs

Switch between related views of the same thing — a teacher’s about, classes and reviews; a festival’s days — without leaving the page.

Demo

Lisandra grew up dancing casino in Havana and has taught Cuban salsa in Munich since 2015. Her classes are playful, musical and big on connection.

vue
<Tabs default-value="about">
  <TabsList>
    <TabsTrigger value="about">About</TabsTrigger>
    <TabsTrigger value="classes">Classes</TabsTrigger>
    <TabsTrigger value="reviews">Reviews</TabsTrigger>
  </TabsList>
  <TabsContent value="about">…</TabsContent>
  <TabsContent value="classes">…</TabsContent>
  <TabsContent value="reviews">…</TabsContent>
</Tabs>

Controlled, full width

Bind v-model when the active tab matters elsewhere (URL, analytics). Stretch the list with grid on phones so every target is wide.

  • 19:00Welcome ruedaMain hall
  • 22:00Opening party — DJ AlöshaMain hall

Active: fri

vue
<script setup lang="ts">
const day = ref('fri')
</script>

<template>
  <Tabs v-model="day">
    <TabsList class="w-full grid grid-cols-3">
      <TabsTrigger value="fri">Fri</TabsTrigger>
      <TabsTrigger value="sat">Sat</TabsTrigger>
      <TabsTrigger value="sun">Sun</TabsTrigger>
    </TabsList>
    <TabsContent v-for="(slots, d) in schedule" :key="d" :value="d">
      <!-- the day's sessions -->
    </TabsContent>
  </Tabs>
</template>

States

Active tabs lift onto the background with a soft shadow. Disabled tabs fade and are skipped by the keyboard.

vue
<TabsTrigger value="videos" disabled>Videos</TabsTrigger>

Props

Parts wrap reka-ui Tabs; their props pass straight through.

PropTypeDefaultDescription
modelValue / v-modelstring | number—Tabs (root). The active tab’s value, controlled.
defaultValuestring | number—Tabs (root). Initial tab when uncontrolled.
orientation'horizontal' | 'vertical''horizontal'Tabs (root). Sets arrow-key direction and aria-orientation. TabsList styles are horizontal — add flex-col yourself for vertical.
activationMode'automatic' | 'manual''automatic'Tabs (root). Automatic switches on arrow focus; manual waits for Enter/Space. Use manual if a panel is slow to render.
valuestring | number—TabsTrigger, TabsContent. Required. Pairs a trigger with its panel.
disabledbooleanfalseTabsTrigger. Greys out (opacity-50) and skips it in keyboard order.
forceMountboolean—TabsContent. Keep the panel in the DOM when hidden (e.g. to preserve a form’s state).
loopbooleantrueTabsList. Arrow keys wrap from the last tab to the first.
classHTMLAttributes["class"]—TabsList, TabsTrigger, TabsContent. Merged with cn().

Do & don't

Do — Two to five short, parallel labels for views of the same thing.

Don't — Use tabs as site navigation or crowd in so many that they scroll off a phone screen.

Accessibility

  • reka-ui renders the WAI-ARIA tabs pattern: role="tablist", role="tab" with aria-selected and aria-controls, and role="tabpanel" labelled by its tab.
  • Keyboard: Tab enters the list on the active tab, ←/→ move between tabs, Home/End jump to the ends. Tab again moves into the panel.
  • Tab labels must be text, not icons alone. If a label truncates at 375px (TabsTrigger truncates long labels), shorten it — “Sat” not “Saturday 24 May”.
  • Tabs hide content. Don’t use them for content people need to compare side by side, or for steps that must happen in order — use a stepper or the page itself.