Skip to content

<re-tabs>

A custom-element wrapper for the tabs pattern, with the same DOM contract as the JS enhancer. element.value reads and writes the selected tab id. See the custom elements overview for how the <re-*> tags work.

Import once to register the tag, then use it declaratively:

import "@relements/core/elements/re-tabs";

Profile content.

Live example
<re-tabs class="re-tabs" id="rt-1" aria-label="Account">
  <div class="re-tabs__list" role="tablist" aria-label="Account">
    <button
      class="re-tab"
      role="tab"
      id="rt-t-profile"
      aria-controls="rt-p-profile"
      aria-selected="true"
    >
      Profile
    </button>
    <button
      class="re-tab"
      role="tab"
      id="rt-t-security"
      aria-controls="rt-p-security"
      aria-selected="false"
      tabindex="-1"
    >
      Security
    </button>
    <button
      class="re-tab"
      role="tab"
      id="rt-t-billing"
      aria-controls="rt-p-billing"
      aria-selected="false"
      tabindex="-1"
    >
      Billing
    </button>
  </div>
  <section
    class="re-tabpanel"
    role="tabpanel"
    id="rt-p-profile"
    aria-labelledby="rt-t-profile"
    tabindex="0"
  >
    <p>Profile content.</p>
  </section>
  <section
    class="re-tabpanel"
    role="tabpanel"
    id="rt-p-security"
    aria-labelledby="rt-t-security"
    tabindex="0"
    hidden
  >
    <p>Security content.</p>
  </section>
  <section
    class="re-tabpanel"
    role="tabpanel"
    id="rt-p-billing"
    aria-labelledby="rt-t-billing"
    tabindex="0"
    hidden
  >
    <p>Billing content.</p>
  </section>
</re-tabs>
  • KeyboardTab moves into the tablist and lands on the selected tab only (roving tabindex: the active tab is tabindex="0", the rest -1); Tab again leaves the list for the panel. Within the list, ArrowLeft/ArrowRight move focus and activate the tab (automatic activation, wrapping at the ends), Home/End jump to the first/last tab and activate it, and Enter/Space activate the focused tab.
  • Focus — both the tabs and the active panel show a visible :focus-visible ring (--re-shadow-focus). Panels carry tabindex="0" so keyboard users can scroll content that has no focusable children.
  • Semanticsrole="tablist" (with aria-label) wraps role="tab" buttons whose aria-selected reflects the current tab and aria-controls points at the matching role="tabpanel"; each panel is aria-labelledby its tab, and inactive panels are hidden. Selecting a tab updates aria-selected/hidden so assistive tech announces the active tab and exposes only the visible panel.
  • Notes — the active-tab underline is a decorative ::after; under forced-colors it is re-painted as the system Highlight color so the selected tab stays distinguishable in Windows High Contrast. See the accessibility guide.