Skip to content
The Membrane Palette
Navigationstable

Tabs

WAI-ARIA tabs — underline or pill (segmented) style; aria-selected drives the visuals, membrane.js adds click and arrow-key behavior.

Examples

Underline tabs

One <link> to membrane.css on jsDelivr.

HTML for “Underline tabs”
<div class="mp-tabs">
  <div class="mp-tabs__list" role="tablist" aria-label="Install options">
    <button class="mp-tabs__tab" type="button" role="tab" id="tabs-cdn" aria-controls="tabs-cdn-panel" aria-selected="true">CDN</button>
    <button class="mp-tabs__tab" type="button" role="tab" id="tabs-copy" aria-controls="tabs-copy-panel" aria-selected="false" tabindex="-1">Copy files</button>
    <button class="mp-tabs__tab" type="button" role="tab" id="tabs-fork" aria-controls="tabs-fork-panel" aria-selected="false" tabindex="-1">Fork</button>
  </div>
  <div class="mp-tabs__panel" role="tabpanel" id="tabs-cdn-panel" aria-labelledby="tabs-cdn" tabindex="0"><p class="type-small">One <code class="mp-code">&lt;link&gt;</code> to <code class="mp-code">membrane.css</code> on jsDelivr.</p></div>
  <div class="mp-tabs__panel" role="tabpanel" id="tabs-copy-panel" aria-labelledby="tabs-copy" tabindex="0" hidden><p class="type-small">Download the three CSS files into your project.</p></div>
  <div class="mp-tabs__panel" role="tabpanel" id="tabs-fork-panel" aria-labelledby="tabs-fork" tabindex="0" hidden><p class="type-small">Edit the JSON source and run the build.</p></div>
</div>

Pill tabs

Warm cream, terracotta emphasis.

HTML for “Pill tabs”
<div class="mp-tabs" data-variant="pill">
  <div class="mp-tabs__list" role="tablist" aria-label="Theme preview">
    <button class="mp-tabs__tab" type="button" role="tab" id="tabs-light" aria-controls="tabs-light-panel" aria-selected="true">Light</button>
    <button class="mp-tabs__tab" type="button" role="tab" id="tabs-dark" aria-controls="tabs-dark-panel" aria-selected="false" tabindex="-1">Dark</button>
  </div>
  <div class="mp-tabs__panel" role="tabpanel" id="tabs-light-panel" aria-labelledby="tabs-light" tabindex="0"><p class="type-small">Warm cream, terracotta emphasis.</p></div>
  <div class="mp-tabs__panel" role="tabpanel" id="tabs-dark-panel" aria-labelledby="tabs-dark" tabindex="0" hidden><p class="type-small">Charcoal depth, lightened accents.</p></div>
</div>

Guidance

Switch between views of related content without leaving the page. The visual state is driven entirely by aria-selected, so the markup and what screen readers hear can't disagree. Load components/membrane.js for behavior (click, Arrow/Home/End keys, RTL); without it, tabs render but don't switch.

When not to use

  • Navigating between pages → links in a Navbar.
  • Content users need to compare side by side → show it all.

Accessibility

  • Required wiring: role="tablist" (with aria-label), role="tab" + aria-controls + aria-selected, role="tabpanel" + aria-labelledby; unselected tabs have tabindex="-1" and their panels hidden.
  • Keyboard (via membrane.js): Tab enters the list on the selected tab; ←/→ move and select (mirrored in RTL); Home/End jump; Tab again moves into the panel.

Manual screen-reader and usability checks have not been recorded for this inventory. See the accessibility evidence for automated coverage, remaining checks and the result-recording protocol.

API

Tabs classes
ClassKind
.mp-tabsroot
.mp-tabs__listpart of .mp-tabs
.mp-tabs__tabpart of .mp-tabs
.mp-tabs__panelpart of .mp-tabs
Tabs attributes
AttributeValues
data-variantpill

States styled: :focus-visible :hover [aria-selected="true"]. Set the native attribute or ARIA state; there are no state classes.

Tabs component tokens
TokenDefaultLight · dark
--mp-tabs-fgvar(--color-text-secondary)#5C564E · #A39D93
--mp-tabs-fg-hovervar(--color-text-primary)#2A2622 · #F0EBE1
--mp-tabs-fg-selectedvar(--color-text-primary)#2A2622 · #F0EBE1
--mp-tabs-bg-hovervar(--color-bg-hover)rgba(42, 38, 34, 0.06) · rgba(240, 235, 225, 0.06)
--mp-tabs-indicatorvar(--color-action-primary)#B35530 · #D4724F
--mp-tabs-trackvar(--color-bg-tertiary)#E2DCD2 · #2E2E34
--mp-tabs-bg-selectedvar(--color-bg-primary)#FAF6EE · #1A1B1F

Design tokens consumed: --border-default --border-width-medium --border-width-thin --color-action-primary --color-bg-hover --color-bg-primary --color-bg-tertiary --color-text-primary --color-text-secondary --elevation-raised --focus-ring --focus-ring-offset --font-sans --radius-full --radius-sm --size-control-md --size-control-sm --size-touch-target --space-1 --space-2 --space-4 --text-small --transition-fast --transition-state --weight-medium

Verified contrast

The build measures each pair for the defaults and for every tone, variant and state that reassigns a token, over page and card surfaces. The ratios below are the worst case in each mode; a pair below its minimum stops the build.

Tabs contrast pairs
UsePairLightDarkMinimum
tab label--mp-tabs-fg on --color-bg-primary6.736.394.5
tab label, hover--mp-tabs-fg-hover on --mp-tabs-bg-hover11.3111.064.5
selected tab label--mp-tabs-fg-selected on --color-bg-primary13.9314.487.0
selected-tab indicator--mp-tabs-indicator on --color-bg-primary4.575.183.0
pill tab label--mp-tabs-fg on --mp-tabs-track5.325.014.5
selected pill tab label--mp-tabs-fg-selected on --mp-tabs-bg-selected13.9314.487.0

Source