Tabs
<div role="tablist">
Organises content into panels accessible via a horizontal tab bar. Two visual styles: underline and pill.
Overview
Preview
Content for Overview tab.
Underline tabs
Preview
html
<div class="flex border-b border-zinc-800">
<!-- Active tab -->
<button class="px-4 py-2.5 text-sm font-medium border-b-2 border-[#D40C37] text-[#D40C37] -mb-px focus:outline-none">
Overview
</button>
<!-- Inactive tab -->
<button class="px-4 py-2.5 text-sm font-medium text-zinc-500 hover:text-zinc-300 transition-colors focus:outline-none">
Analytics
</button>
</div>Pill tabs
Preview
html
<div class="flex gap-1 rounded-lg bg-zinc-900 p-1">
<!-- Active -->
<button class="rounded-md px-3 py-1.5 text-sm font-medium bg-zinc-700 text-zinc-100 shadow-sm focus:outline-none">
Day
</button>
<!-- Inactive -->
<button class="rounded-md px-3 py-1.5 text-sm font-medium text-zinc-500 hover:text-zinc-300 transition-colors focus:outline-none">
Week
</button>
</div>With Vue reactivity
vue
<script setup>
import { ref } from 'vue'
const tabs = ['Overview', 'Analytics', 'Settings']
const active = ref('Overview')
</script>
<template>
<div>
<div class="flex border-b border-zinc-800">
<button
v-for="tab in tabs"
:key="tab"
@click="active = tab"
:class="['px-4 py-2.5 text-sm font-medium transition-colors focus:outline-none',
active === tab ? 'border-b-2 border-[#D40C37] text-[#D40C37] -mb-px' : 'text-zinc-500 hover:text-zinc-300']"
>{{ tab }}</button>
</div>
<div class="mt-4 p-4 rounded-lg border border-zinc-800 bg-zinc-900/40 text-sm text-zinc-400">
Content for {{ active }}
</div>
</div>
</template>With Headless UI (recommended for production)
vue
<script setup>
import { TabGroup, TabList, Tab, TabPanels, TabPanel } from '@headlessui/vue'
</script>
<template>
<TabGroup>
<TabList class="flex border-b border-zinc-800">
<Tab v-for="tab in ['Overview', 'Analytics']" :key="tab" v-slot="{ selected }" as="template">
<button :class="['px-4 py-2.5 text-sm font-medium transition-colors focus:outline-none -mb-px',
selected ? 'border-b-2 border-[#D40C37] text-[#D40C37]' : 'text-zinc-500 hover:text-zinc-300']">
{{ tab }}
</button>
</Tab>
</TabList>
<TabPanels class="mt-4">
<TabPanel>Overview content</TabPanel>
<TabPanel>Analytics content</TabPanel>
</TabPanels>
</TabGroup>
</template>Accessibility notes
- Use
role="tablist"on the container,role="tab"on each button,role="tabpanel"on each panel - Link tabs to panels with
aria-controlsandid - Active tab should have
aria-selected="true" - Headless UI's
<TabGroup>handles all of this automatically