Skip to content

Tabs

Width Open in a tab
The classes below, on plain markup, in their own document — so what you are looking at is core's stylesheet and nothing else.
The markup
<div class="aparte-tabs aparte-tabs--underline" role="tablist" aria-label="Result view">
<button class="aparte-tabs__tab" role="tab" type="button" id="tabs-u-preview" aria-controls="tabs-u-preview-panel" aria-selected="true" tabindex="0">Preview</button>
<button class="aparte-tabs__tab" role="tab" type="button" id="tabs-u-code" aria-controls="tabs-u-code-panel" aria-selected="false" tabindex="-1">Code</button>
</div>
<div class="aparte-tabs__panel" role="tabpanel" id="tabs-u-preview-panel" aria-labelledby="tabs-u-preview">What the selected tab shows.</div>
<div class="aparte-tabs__panel" role="tabpanel" id="tabs-u-code-panel" aria-labelledby="tabs-u-code" hidden>What the other tab shows.</div>
<div class="aparte-tabs aparte-tabs--segmented" role="tablist" aria-label="Theme">
<button class="aparte-tabs__tab" role="tab" type="button" id="tabs-s-light" aria-controls="tabs-s-light-panel" aria-selected="true" tabindex="0">Light</button>
<button class="aparte-tabs__tab" role="tab" type="button" id="tabs-s-dark" aria-controls="tabs-s-dark-panel" aria-selected="false" tabindex="-1">Dark</button>
<button class="aparte-tabs__tab" role="tab" type="button" id="tabs-s-system" aria-controls="tabs-s-system-panel" aria-selected="false" tabindex="-1">System</button>
</div>
<div class="aparte-tabs__panel" role="tabpanel" id="tabs-s-light-panel" aria-labelledby="tabs-s-light">The light theme's settings.</div>
<div class="aparte-tabs__panel" role="tabpanel" id="tabs-s-dark-panel" aria-labelledby="tabs-s-dark" hidden>The dark theme's settings.</div>
<div class="aparte-tabs__panel" role="tabpanel" id="tabs-s-system-panel" aria-labelledby="tabs-s-system" hidden>Whatever the system asks for.</div>

One row of tabs, and the panel under it

Two looks, one behaviour. --underline marks the current tab with a rule beneath it and is the quieter of the two; --segmented puts the whole row in a track and fills the current tab, which reads as a control rather than as navigation. Neither moves anything: aria-selected is what says which tab is current, and the app owns it.

The markup below is the whole contract of the role, and all of it is yours to write: ONE tab stop for the list (tabindex="0" on the selected tab, -1 on the rest), aria-controls from each tab to its role="tabpanel", and aria-labelledby back. The app also owns the ArrowLeft/ArrowRight/Home/End handler that moves the selection and the stop together — @aparte/plugin-artifacts’ card has a working one to copy. A tablist without those is louder than plain buttons and says less: every tab a tab stop, and none of them naming what it opens.

.aparte-tabs · .aparte-tabs--segmented · .aparte-tabs--underline · .aparte-tabs__panel · .aparte-tabs__tab

The tokens these read are on the CSS variables reference; every class of the kit, on one page, is the classes reference.