Tabs
The ARIA tabs pattern. The initial state is server-rendered; the enhanceTabs behavior adds keyboard navigation. Prefer a self-managing tag? The <re-tabs> custom element wraps this same pattern.
Manage your name and email here.
Two-factor authentication, password rotation, sessions.
Plan, invoices, payment method.
<div class="re-tabs" data-re-tabs id="tabs-1">
<div class="re-tabs__list" role="tablist" aria-label="Account">
<button
class="re-tab"
role="tab"
id="t-profile"
aria-controls="p-profile"
aria-selected="true"
>
Profile
</button>
<button
class="re-tab"
role="tab"
id="t-security"
aria-controls="p-security"
aria-selected="false"
tabindex="-1"
>
Security
</button>
<button
class="re-tab"
role="tab"
id="t-billing"
aria-controls="p-billing"
aria-selected="false"
tabindex="-1"
>
Billing
</button>
</div>
<section
class="re-tabpanel"
role="tabpanel"
id="p-profile"
aria-labelledby="t-profile"
tabindex="0"
>
<p>Manage your name and email here.</p>
</section>
<section
class="re-tabpanel"
role="tabpanel"
id="p-security"
aria-labelledby="t-security"
tabindex="0"
hidden
>
<p>Two-factor authentication, password rotation, sessions.</p>
</section>
<section
class="re-tabpanel"
role="tabpanel"
id="p-billing"
aria-labelledby="t-billing"
tabindex="0"
hidden
>
<p>Plan, invoices, payment method.</p>
</section>
</div> Accessibility
Section titled “Accessibility”- Keyboard —
Tabenters the tablist and lands on the selected tab only (rovingtabindex:enhanceTabskeeps the active tab attabindex="0"and the rest at-1);Tabagain moves out to the panel. Within the list,ArrowLeft/ArrowRightmove focus and activate the tab — automatic activation, wrapping past the ends —Home/Endjump to the first/last tab and activate it, andEnter/Spaceactivate the focused tab. Without JavaScript the server-rendered selected panel stays visible and the page remains usable; the keyboard navigation is the only thing the behavior adds. - Focus — both the tabs and the active panel show a visible
:focus-visiblering (--re-shadow-focus, replacing the default outline). Each panel carriestabindex="0"so keyboard users can focus and scroll a panel that has no focusable children of its own. - Semantics —
role="tablist"(labelled witharia-label) wrapsrole="tab"buttons whosearia-selectedmarks the current tab and whosearia-controlspoints at the matchingrole="tabpanel"; each panel isaria-labelledbyits tab, and inactive panels arehidden. Selecting a tab updatesaria-selectedand toggleshidden, so assistive tech announces the active tab and exposes only the visible panel. - Notes — the active-tab underline is a decorative
::afterand conveys nothing on its own (aria-selectedcarries the state); underforced-colors: activeit is re-painted as the systemHighlightcolor so the selected tab stays distinguishable in Windows High Contrast. The cancelablere-changeevent lets you veto a tab switch without breaking these semantics. See the accessibility guide for the project-wide stance.