Menu
Overview
General
ButtonBadgePillsAvatarBrand lockupLayout
ContainerGrid & RowSurface & text utilitiesApp shellPage headerData Display
CardTableChartsCalendarStatsBulletsLeadersLogo wallCollapse & DisclosureTimelineValue chainDescriptionsFeedback
AlertProgressModalSlide-overSkeletonEmpty stateForms
Field & InputDropdownLead form & CTA rowDate pickerFilter barNavigation
NavSide navigationTop navigationApp switcherUser menuStepperTabsBreadcrumbPaginationTemplates
Sign-in pageSigned-out pageSettings layoutTheming
Browser tabProduct themesNavigation
Tabs
Facet switcher on native radio inputs; the selected tab takes the accent colour and a 2px rule, hover lifts the rest. Works with JavaScript off.
.tabs · .tabs__list · .tabs__tab · .tabs__panel · native radio + :has pattern
Merchant standing, limits, and contacts live here.
Settlement history for the last 90 days.
Two active keys; rotation due next quarter.
Every state change on this merchant, oldest first.
<div class="tabs">
<div class="tabs__list" role="radiogroup" aria-label="Merchant sections">
<label class="tabs__tab"><input type="radio" name="mtab" checked>Overview</label>
<label class="tabs__tab"><input type="radio" name="mtab">History</label>
<label class="tabs__tab"><input type="radio" name="mtab">API keys</label>
<label class="tabs__tab"><input type="radio" name="mtab">Audit log <span class="badge">12</span></label>
</div>
<section class="tabs__panel"><p style="margin:0">Merchant standing, limits, and contacts live here.</p></section>
<section class="tabs__panel"><p style="margin:0">Settlement history for the last 90 days.</p></section>
<section class="tabs__panel"><p style="margin:0">Two active keys; rotation due next quarter.</p></section>
<section class="tabs__panel"><p style="margin:0">Every state change on this merchant, oldest first.</p></section>
</div>
Usage
- Tabs are native radio inputs switched by CSS
:has(): no JavaScript, arrow keys move between them, and where:hasis unsupported every panel shows at once rather than vanishing. - Each
.tabs__tablabel wraps its own radio input, so there are no ids to keep in sync;:has(input:checked)drives the colour and each.tabs__panelmatches its tab by order. - Colour carries three states: idle is
--text-secondary, hover lifts to--texton--bg-subtle, and the selected tab takes--accent-textover a 2px--accentrule that slides in under its label. - The active mark is an underline, not a fill. A fill belongs to
.btn; a filled tab reads as a button and spends the accent the page is supposed to spend once. - Counts sit inside the tab as a
.badge, so the number rides with the label instead of floating beside it. - The radio is visually hidden but keeps its focus ring, drawn on the label with
focus-visible. Neverdisplay:nonethe input or keyboard users lose the tab bar. - Tabs divide one subject into facets. For moving between subjects use navigation; for a linear flow use the stepper.
- Keep labels to one or two words; the CSS matches up to six.