Skip to content

Tabs

Switch between related content sections. Three minimalist variants: underline, segment, and pill.


Demo

Underline (default)

Oversigt over systemets status og nøgletal.

Segment

Vue 3 komponentbibliotek med Composition API.

Pill

Viser alle komponenter i biblioteket.

With icons


When to use

  • Content has clear groupings that benefit from chunking
  • Users need only one section at a time — not simultaneous comparison
  • Few tabs (max 5–7) with short, scannable labels

When not to use

  • Sequential flows or step-by-step processes — use a step indicator
  • Users need to compare content across tabs — show all content or use a table
  • More than 7 groupings — consider separate pages
  • Content lacks distinct logical groupings

Installation

bash
pnpm add @grundtone/vue

Usage

Underline (default)

vue
<template>
  <GTTabs :tabs="[
    { id: 'overview', label: 'Overview' },
    { id: 'details', label: 'Details' },
  ]">
    <GTTabPanel id="overview"><p>Overview content.</p></GTTabPanel>
    <GTTabPanel id="details"><p>Details content.</p></GTTabPanel>
  </GTTabs>
</template>

Segment

vue
<template>
  <GTTabs variant="segment" :tabs="tabs">
    <GTTabPanel id="vue"><p>Vue content.</p></GTTabPanel>
    <GTTabPanel id="nuxt"><p>Nuxt content.</p></GTTabPanel>
  </GTTabs>
</template>

Pill

vue
<template>
  <GTTabs variant="pill" :tabs="tabs">
    <GTTabPanel id="all"><p>All items.</p></GTTabPanel>
    <GTTabPanel id="active"><p>Active items.</p></GTTabPanel>
  </GTTabs>
</template>

With icons

vue
<template>
  <GTTabs :tabs="[
    { id: 'search', label: 'Search', icon: 'search' },
    { id: 'done', label: 'Done', icon: 'check' },
  ]">
    <GTTabPanel id="search"><p>Search results.</p></GTTabPanel>
    <GTTabPanel id="done"><p>Completed items.</p></GTTabPanel>
  </GTTabs>
</template>

GTTabs Props

PropTypeDefaultDescription
tabsTabItem[]requiredTab definitions
modelValuestringfirst tab IDActive tab (v-model)
variant'underline' | 'segment' | 'pill''underline'Visual variant
ariaLabelstring'Faner'Accessible label for tab list

TabItem

PropertyTypeDescription
idstringUnique identifier
labelstringTab label text
iconstringOptional icon name (all tabs must have icon if one does)

GTTabPanel Props

PropTypeDescription
idstringMust match a TabItem.id

Events

EventPayloadDescription
update:modelValuestringActive tab changed

Accessibility

  • role="tablist" on tab bar, role="tab" on each button, role="tabpanel" on panels
  • aria-selected, aria-controls, aria-labelledby properly linked
  • Keyboard: Arrow left/right cycles tabs, Home/End jumps to first/last, Enter/Space activates
  • Active tab has tabindex="0", inactive tabs have tabindex="-1" (roving tabindex)
  • No disabled tabs — all tabs are always visible and active
  • Icons must always be paired with text labels

CSS Classes

ClassElement
.gt-tabsRoot container
.gt-tabs--underlineUnderline variant
.gt-tabs--segmentSegment variant
.gt-tabs--pillPill variant
.gt-tabs__listTab button row
.gt-tabs__tabSingle tab button
.gt-tabs__tab--activeActive tab
.gt-tabs__iconTab icon
.gt-tabs__panelContent panel

Design system

The CSS-only version is documented in the Design System — Tabs reference.