tabs vertical pill navigation features product sidebar-tabs tabs vertical pill navigation features categories sidebar switcher vertical pill tab navigation feature category tabs with image preview sidebar tab switcher
Tabs Vertical Pill
Fetch pattern JSON:
curl https://webspire.de/patterns/tabs/vertical-pill.json vertical-pill.html
<section class="ws-tabs bg-[var(--ws-color-bg)] py-20">
<div class="mx-auto max-w-7xl px-6">
<div class="mx-auto max-w-2xl text-center">
<h2 class="text-3xl font-bold tracking-tight text-[var(--ws-color-text)] sm:text-4xl">Everything you need</h2>
<p class="mt-4 text-base text-[var(--ws-color-text-soft)]">Explore features across all categories.</p>
</div>
<!-- Mobile: horizontal scrollable chips -->
<div class="mt-8 flex gap-2 overflow-x-auto pb-2 lg:hidden" role="tablist" aria-label="Feature categories">
<button role="tab" aria-selected="true" class="shrink-0 rounded-full bg-[var(--ws-color-accent)] px-4 py-2 text-sm font-semibold text-white">Analytics</button>
<button role="tab" aria-selected="false" class="shrink-0 rounded-full bg-[var(--ws-color-bg-secondary)] px-4 py-2 text-sm font-medium text-[var(--ws-color-text-soft)] hover:text-[var(--ws-color-text)] transition-colors">Automation</button>
<button role="tab" aria-selected="false" class="shrink-0 rounded-full bg-[var(--ws-color-bg-secondary)] px-4 py-2 text-sm font-medium text-[var(--ws-color-text-soft)] hover:text-[var(--ws-color-text)] transition-colors">Integrations</button>
<button role="tab" aria-selected="false" class="shrink-0 rounded-full bg-[var(--ws-color-bg-secondary)] px-4 py-2 text-sm font-medium text-[var(--ws-color-text-soft)] hover:text-[var(--ws-color-text)] transition-colors">Security</button>
</div>
<!-- Desktop: vertical pill nav + content -->
<div class="mt-8 grid gap-8 lg:grid-cols-[220px_1fr]">
<!-- Left: vertical pill tabs -->
<nav class="hidden lg:flex lg:flex-col lg:gap-1" role="tablist" aria-label="Feature categories" aria-orientation="vertical">
<!-- Active tab -->
<button role="tab" aria-selected="true" class="flex w-full items-center gap-3 rounded-xl bg-[var(--ws-color-accent)] px-4 py-3 text-left text-sm font-semibold text-white transition-all">
<svg class="h-5 w-5 shrink-0" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 013 19.875v-6.75zM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V8.625zM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V4.125z"/>
</svg>
Analytics
</button>
<!-- Inactive tabs -->
<button role="tab" aria-selected="false" class="flex w-full items-center gap-3 rounded-xl bg-transparent px-4 py-3 text-left text-sm font-medium text-[var(--ws-color-text-soft)] transition-all hover:bg-[var(--ws-color-bg-secondary)] hover:text-[var(--ws-color-text)]">
<svg class="h-5 w-5 shrink-0" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.325.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.241-.438.613-.43.992a7.723 7.723 0 010 .255c-.008.378.137.75.43.991l1.004.827c.424.35.534.955.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.47 6.47 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.281c-.09.543-.56.94-1.11.94h-2.594c-.55 0-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.991a6.932 6.932 0 010-.255c.007-.38-.138-.751-.43-.992l-1.004-.827a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.086.22-.128.332-.183.582-.495.644-.869l.214-1.28z"/>
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
</svg>
Automation
</button>
<button role="tab" aria-selected="false" class="flex w-full items-center gap-3 rounded-xl bg-transparent px-4 py-3 text-left text-sm font-medium text-[var(--ws-color-text-soft)] transition-all hover:bg-[var(--ws-color-bg-secondary)] hover:text-[var(--ws-color-text)]">
<svg class="h-5 w-5 shrink-0" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"/>
</svg>
Integrations
</button>
<button role="tab" aria-selected="false" class="flex w-full items-center gap-3 rounded-xl bg-transparent px-4 py-3 text-left text-sm font-medium text-[var(--ws-color-text-soft)] transition-all hover:bg-[var(--ws-color-bg-secondary)] hover:text-[var(--ws-color-text)]">
<svg class="h-5 w-5 shrink-0" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75m-3-7.036A11.959 11.959 0 013.598 6 11.99 11.99 0 003 9.749c0 5.592 3.824 10.29 9 11.623 5.176-1.332 9-6.03 9-11.622 0-1.31-.21-2.571-.598-3.751h-.152c-3.196 0-6.1-1.248-8.25-3.285z"/>
</svg>
Security
</button>
</nav>
<!-- Right: active tab content -->
<div class="rounded-2xl bg-[var(--ws-color-bg-secondary)] p-2" role="tabpanel">
<!-- Image placeholder -->
<div class="aspect-video w-full overflow-hidden rounded-xl bg-gradient-to-br from-violet-500 via-purple-500 to-indigo-600 flex items-center justify-center">
<div class="text-center text-white/80">
<svg class="mx-auto h-16 w-16 opacity-60" fill="none" stroke="currentColor" stroke-width="1" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909M3 20.25h18M3 20.25V6.75A2.25 2.25 0 015.25 4.5h13.5A2.25 2.25 0 0121 6.75v13.5"/>
</svg>
<p class="mt-3 text-sm font-medium opacity-70">Feature preview</p>
</div>
</div>
<!-- Content -->
<div class="p-6">
<h3 class="text-xl font-bold text-[var(--ws-color-text)]">Powerful Analytics Dashboard</h3>
<p class="mt-2 text-sm leading-relaxed text-[var(--ws-color-text-soft)]">
Get real-time insights into your business performance. Track key metrics, visualize trends, and make data-driven decisions with our intuitive analytics suite.
</p>
<a href="#" class="mt-4 inline-flex items-center gap-1.5 text-sm font-semibold text-[var(--ws-color-accent)] hover:underline">
Learn more
<svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M13.5 4.5L21 12m0 0l-7.5 7.5M21 12H3"/></svg>
</a>
</div>
</div>
</div>
</div>
</section>
Details
Responsive Dark Mode Tailwind Only SSR Safe Copy & Paste
Stable Published
tabsverticalpillnavigationfeaturesproductsidebar-tabs
Slots
| Name | Required | Description |
|---|---|---|
| heading | Yes | Section heading and subtext. |
| tab-nav | Yes | Vertical list of pill-style tab buttons with icon and label. |
| tab-content | Yes | Right panel with image placeholder, title, and description. |
Props
| Name | Type | Default | Description |
|---|---|---|---|
| activeTab | string | first | Controls which tab is shown as active. |
Vertical pill-style tab navigation on the left (desktop) with an image preview and description on the right. Mobile falls back to horizontal scrollable chip tabs. Add JS to switch active tab and update the right panel content dynamically.