Skip to content

Tabs

Account

Make changes to your account here.

Password

Change your password here.

<div class="tabs">
<div class="tabs-list">
<button class="tabs-trigger" type="button">Account</button>
<button class="tabs-trigger" type="button">Password</button>
</div>
<div class="tabs-content"></div>
<div class="tabs-content"></div>
</div>

Triggers and panels are paired in order, so there are no ids to keep in sync. partialkit adds the roles, the roving tab order and the arrow keys; write aria-controls yourself if the panels are not siblings of the list.

ClassPart
.tabsThe wrapper
.tabs-listThe row of triggers
.tabs-triggerOne tab
.tabs-contentIts panel
AttributeOnMeaning
data-variant="line".tabs-listUnderline instead of the raised pill
data-orientation="vertical".tabsList beside the panel, arrows move up and down
data-activation="manual".tabsArrows move focus; Enter or Space selects
data-active.tabs-triggerWhich tab starts selected
disabled.tabs-triggerSkipped by the arrow keys

Everything at a glance.

What happened lately.

How it all behaves.

Name, description and visibility.

Who can see and edit this project.

Plan, invoices and payment method.

Numbers, charts and the usual.

Everyone with access.

Not reachable.

Selecting a tab fires pk:tabs:change on the trigger, carrying data-value — enough to load a panel’s contents on first open.

document.addEventListener("pk:tabs:change", (event) => {
console.log(event.detail.value);
});

Set dir="rtl" on the page or on any subtree — the arrow keys follow the reading direction, so Left moves forward. See the button page for a live example.

  • The list is a tablist, each trigger a tab, each panel a tabpanel — applied for you, along with aria-selected and aria-controls.
  • One stop in the tab order. Tab reaches the selected trigger, then the panel; arrows move between tabs. Tabbing through six triggers to reach the content is the mistake this pattern exists to avoid.
  • Panels are focusable. tabindex="0" means a panel with nothing but text can still be reached and scrolled by keyboard.
  • Automatic activation by default, which matches the platform and shadcn/ui. Switch to data-activation="manual" when a panel is expensive to load, so arrowing past it costs nothing.
  • A disabled tab stays announced. It is skipped by the arrow keys but still read, which tells people it exists — unlike removing it.