Tab Group
layoutUSWDS-derivedinteractive
A tabbed interface for switching between content panels. Progressively enhanced from stacked content.
Reference: USWDS documentation ↗
Variants
Default Tabs
First panel content.
Second panel content.
Third panel content.
<flex-tab-group>
<div role="tablist" aria-label="Default example">
<button type="button" role="tab" aria-selected="true" aria-controls="tab-group-1066-panel-0" id="tab-group-1066-tab-0" class="flex-tab-group__tab">First</button>
<button type="button" role="tab" aria-selected="false" aria-controls="tab-group-1066-panel-1" id="tab-group-1066-tab-1" tabindex="-1" class="flex-tab-group__tab">Second</button>
<button type="button" role="tab" aria-selected="false" aria-controls="tab-group-1066-panel-2" id="tab-group-1066-tab-2" tabindex="-1" class="flex-tab-group__tab">Third</button>
</div>
<div role="tabpanel" id="tab-group-1066-panel-0" aria-labelledby="tab-group-1066-tab-0" class="flex-tab-group__panel">
<p>First panel content.</p>
</div>
<div role="tabpanel" id="tab-group-1066-panel-1" aria-labelledby="tab-group-1066-tab-1" hidden="" class="flex-tab-group__panel">
<p>Second panel content.</p>
</div>
<div role="tabpanel" id="tab-group-1066-panel-2" aria-labelledby="tab-group-1066-tab-2" hidden="" class="flex-tab-group__panel">
<p>Third panel content.</p>
</div>
</flex-tab-group>Two Tabs
This is the preview.
<p>This is the preview.</p><flex-tab-group>
<div role="tablist" aria-label="Two tab example">
<button type="button" role="tab" aria-selected="true" aria-controls="tab-group-1067-panel-0" id="tab-group-1067-tab-0" class="flex-tab-group__tab">Preview</button>
<button type="button" role="tab" aria-selected="false" aria-controls="tab-group-1067-panel-1" id="tab-group-1067-tab-1" tabindex="-1" class="flex-tab-group__tab">Code</button>
</div>
<div role="tabpanel" id="tab-group-1067-panel-0" aria-labelledby="tab-group-1067-tab-0" class="flex-tab-group__panel">
<p>This is the preview.</p>
</div>
<div role="tabpanel" id="tab-group-1067-panel-1" aria-labelledby="tab-group-1067-tab-1" hidden="" class="flex-tab-group__panel">
<pre><code><p>This is the preview.</p></code></pre>
</div>
</flex-tab-group>Contract
Class mapping
| USWDS | Flex | Notes |
|---|---|---|
usa-tab | <flex-tab-group> (custom element) | Container element |
usa-tab [role="tablist"] | flex-tab-group [role="tablist"] | Tab list wrapper with ARIA role |
[role="tab"] | .flex-tab-group__tab | Individual tab button |
[role="tabpanel"] | .flex-tab-group__panel | Tab panel content area |
Verified properties
font-familycursorBehavior promises
- ✓ Click switches active panel
- ✓ Arrow keys navigate between tabs
- ✓ Home key moves focus to first tab
- ✓ End key moves focus to last tab
- ✓ Arrow keys wrap around at edges
- ✓ Accessibility audit passes
Source CSS
flex-tab-group {
display: block;
[role="tablist"] {
display: flex;
border-block-end: 1px solid var(--flex-color-border);
gap: 0;
}
}
.flex-tab-group__tab {
padding: var(--flex-space-sm) var(--flex-space-md);
background: none;
border: 1px solid transparent;
border-block-end: none;
font-size: var(--flex-text-uswds);
font-weight: 700;
color: var(--flex-color-text-muted);
cursor: pointer;
position: relative;
inset-block-start: 1px;
&:hover {
color: var(--flex-color-text);
}
&:focus-visible {
outline: var(--flex-focus-ring);
outline-offset: -2px;
z-index: 1;
}
&[aria-selected="true"] {
color: var(--flex-color-text);
border-color: var(--flex-color-border);
background: var(--flex-color-bg);
border-block-end-color: var(--flex-color-bg);
}
}
.flex-tab-group__panel {
padding: var(--flex-space-md);
border: 1px solid var(--flex-color-border);
border-block-start: none;
&[hidden] {
display: none;
}
}
A digital services project by Flexion