Skip to content
Gloss v2.0.0
Source
Components

Tabs

Two real variants: underline for primary section navigation, segmented for filters. The WAI-ARIA tabs pattern, wired up in vanilla JavaScript — arrows move, Home/End jump to the ends.

Tabs follows the real WAI-ARIA tabs pattern: [role="tablist"] contains [role="tab"] buttons controlling [role="tabpanel"]s. Those roles are required for the pattern to be accessible in the first place, so they are the entire styling contract too — no classes anywhere in this component. The keyboard wiring (assets/js/system.js) only looks for [data-tabs] / [role=tab], so the root wrapper keeps that one data attribute and needs nothing else.

Underline

Mono, with an accent underline. For primary section navigation — a project’s own tabs, never a filter. This is the default; no data-variant needed.

Underline
Repository contents.
Markup
<div data-tabs="">
  <div role="tablist" aria-label="Repository">
    <button role="tab" id="tabs-code-tab" aria-controls="tabs-code-panel" aria-selected="true" tabindex="0">Code</button>
    <button role="tab" id="tabs-ci-tab" aria-controls="tabs-ci-panel" aria-selected="false" tabindex="-1">CI</button>
    <button role="tab" id="tabs-issues-tab" aria-controls="tabs-issues-panel" aria-selected="false" tabindex="-1">Issues</button>
  </div>
  <div role="tabpanel" id="tabs-code-panel" aria-labelledby="tabs-code-tab" tabindex="0">Repository contents.</div>
  <div role="tabpanel" id="tabs-ci-panel" aria-labelledby="tabs-ci-tab" tabindex="0" hidden="">Build history.</div>
  <div role="tabpanel" id="tabs-issues-panel" aria-labelledby="tabs-issues-tab" tabindex="0" hidden="">Open issues.</div>
</div>

Segmented

A pill track; the active segment lifts to the surface. For filters — All · Overdue · Upcoming — never primary navigation. data-variant="segmented" on the tablist is the only attribute either variant needs, since neither has a natural one of its own.

Segmented
7 series.
Markup
<div data-tabs="">
  <div role="tablist" data-variant="segmented" aria-label="Filter">
    <button role="tab" id="tabs-all-tab" aria-controls="tabs-all-panel" aria-selected="true" tabindex="0">All</button>
    <button role="tab" id="tabs-overdue-tab" aria-controls="tabs-overdue-panel" aria-selected="false" tabindex="-1">Overdue</button>
    <button role="tab" id="tabs-upcoming-tab" aria-controls="tabs-upcoming-panel" aria-selected="false" tabindex="-1">Upcoming</button>
  </div>
  <div role="tabpanel" id="tabs-all-panel" aria-labelledby="tabs-all-tab" tabindex="0">7 series.</div>
  <div role="tabpanel" id="tabs-overdue-panel" aria-labelledby="tabs-overdue-tab" tabindex="0" hidden="">2 series.</div>
  <div role="tabpanel" id="tabs-upcoming-panel" aria-labelledby="tabs-upcoming-tab" tabindex="0" hidden="">5 series.</div>
</div>

Rules

API

Element / attributeValuesNotes
[data-tabs]Required on the root wrapper — what the keyboard wiring in system.js looks for.
[role="tablist"]Required. Contains the tab buttons.
[role="tab"]Required, one per item. aria-selected and tabindex are managed by the JS.
[role="tabpanel"]Required, one per item, referenced by the tab's aria-controls.
data-variantsegmentedOn the tablist. Omit for the default underline look.