Tabs
Switch between related panels while keeping one context in view.
Try it
<hui-tabs id="playground-tabs" value="profile" aria-label="Account settings">
<hui-tabs-list>
<hui-tabs-tab value="profile">Profile</hui-tabs-tab>
<hui-tabs-tab value="security">Security</hui-tabs-tab>
<hui-tabs-tab value="billing">Billing</hui-tabs-tab>
</hui-tabs-list>
<hui-tabs-panel value="profile">Your profile details.</hui-tabs-panel>
<hui-tabs-panel value="security">Security settings.</hui-tabs-panel>
<hui-tabs-panel value="billing">Billing preferences.</hui-tabs-panel>
</hui-tabs>- data-state
- Waiting for enhancement
No component events yet.
Usage
Use hui-tabs for a set of related panels where one panel is visible at a time. The root value attribute is the selection source of truth. Values are stable strings supplied on each tab and matching panel. The component does not animate or measure panels; consumers may style data-state and data-orientation hooks.
Anatomy
- Root:
hui-tabs - List:
hui-tabs-listrenders atablistlandmark - Tab:
hui-tabs-tabrenders a nativebutton[role="tab"] - Panel:
hui-tabs-panelrenders atabpanelregion - State hooks: tabs and panels use
data-state="active|inactive"; inactive panels havehidden - Orientation hook: the root and list expose
data-orientation="horizontal|vertical"
Examples
<section aria-labelledby="tabs-heading">
<h2 id="tabs-heading">Account settings</h2>
<hui-tabs id="account-tabs" value="profile" aria-label="Account settings" loop>
<hui-tabs-list>
<hui-tabs-tab value="profile"><b>Profile</b></hui-tabs-tab>
<hui-tabs-tab value="security">Security</hui-tabs-tab>
<hui-tabs-tab value="billing" disabled>Billing</hui-tabs-tab>
</hui-tabs-list>
<hui-tabs-panel value="profile">Update your profile details.</hui-tabs-panel>
<hui-tabs-panel value="security">Manage your password and security settings.</hui-tabs-panel>
<hui-tabs-panel value="billing">Review invoices and payment methods.</hui-tabs-panel>
</hui-tabs>
</section>API reference
Root attributes
| Attribute | Meaning |
|---|---|
value | Active tab value. If omitted, the first enabled tab is selected. |
orientation | horizontal (default) or vertical; controls ARIA and arrow-key navigation. |
activation | automatic (default) selects while moving focus, or manual selects on Enter/Space/click. |
loop | Allows arrow-key navigation to wrap from the last tab to the first. |
aria-label, aria-labelledby, aria-describedby | Naming and description forwarded to the tab list. |
Tab attributes
| Attribute | Meaning |
|---|---|
value | Stable value matched by the root and panel. |
disabled | Removes the tab from keyboard navigation and prevents selection. |
aria-label, aria-labelledby, aria-describedby | Optional accessible naming forwarded to the native tab button. |
Panel attributes
| Attribute | Meaning |
|---|---|
value | Stable value matching a tab. |
aria-label, aria-labelledby | Optional panel naming; generated relationships are added when deterministic IDs exist. |
Events:
hui-value-change: emitted by the root with{ value: string | undefined }.
States and styling
| State | Contract and styling guidance |
|---|---|
| Active tab | Native tab has aria-selected="true", tabindex="0", and its panel is visible. |
| Inactive tab | Native tab has aria-selected="false", tabindex="-1"; its panel has hidden. |
| Hover | Style tabs with --hui-color-interactive-hover. |
| Active | Style the selected tab with --hui-color-interactive. |
| Focus | Keep a visible focus ring using --hui-color-focus-ring. |
| Disabled | Native button is disabled and marked aria-disabled="true"; navigation skips it. |
Attributes are the source of truth. Style derived state with data-state, ARIA attributes, and the --hui-* token aliases.
Accessibility and keyboard support
- Horizontal tabs use
ArrowLeftandArrowRight; vertical tabs useArrowUpandArrowDown. - In RTL, horizontal arrow meaning is inverted.
HomeandEndfocus the first and last enabled tab.- Arrow navigation wraps only when
loopis present. activation="automatic"selects the focused tab;activation="manual"waits forEnterorSpace. Clicking an enabled tab always selects it.- Focus remains on the tab after selection. Panels are not focus-trapped.
SSR and forms
SSR emits the complete tablist, tabs, and panels. The selected tab has resolved aria-selected="true"; inactive panels have hidden="hidden"; ARIA relationships use IDs derived from stable root/value attributes or are omitted when no deterministic ID is available. The value attribute is the server seed and is preserved through adoption. Without JavaScript, native tab buttons and the server-selected panel remain usable as a static presentation; consumers may remove hidden to expose every panel.
Code
<hui-tabs id="account-tabs" value="profile" aria-label="Account settings">
<hui-tabs-list>
<hui-tabs-tab value="profile">Profile</hui-tabs-tab>
<hui-tabs-tab value="security">Security</hui-tabs-tab>
</hui-tabs-list>
<hui-tabs-panel value="profile">Your profile.</hui-tabs-panel>
<hui-tabs-panel value="security">Security settings.</hui-tabs-panel>
</hui-tabs>
<hui-tabs id="playground-tabs" value="profile" aria-label="Account settings">
<hui-tabs-list>
<hui-tabs-tab value="profile">Profile</hui-tabs-tab>
<hui-tabs-tab value="security">Security</hui-tabs-tab>
<hui-tabs-tab value="billing">Billing</hui-tabs-tab>
</hui-tabs-list>
<hui-tabs-panel value="profile">Your profile details.</hui-tabs-panel>
<hui-tabs-panel value="security">Security settings.</hui-tabs-panel>
<hui-tabs-panel value="billing">Billing preferences.</hui-tabs-panel>
</hui-tabs>