Tabs

In-place panel switcher using real tab semantics, with roving tabindex and arrow-key navigation.

  • Use real tab semantics when panels switch in place.
  • Use normal links and aria-current="page" for page navigation that only looks like tabs.
  • JavaScript owns roving tabindex, aria-selected, hidden, and keyboard behavior.
  • Left/Right select tabs and wrap at the ends. Home/End jump to first/last. Down moves focus into the selected panel.
  • A tab list needs both .tabs and role="tablist"; .tab styles each trigger.
General content
<div class="tabset">
  <div class="tabs" role="tablist" aria-label="Settings">
    <button class="tab primary"
            type="button"
            role="tab"
            aria-selected="true"
            aria-controls="panel-general"
            id="tab-general">
      General
    </button>
    <button class="tab"
            type="button"
            role="tab"
            aria-selected="false"
            aria-controls="panel-security"
            id="tab-security"
            tabindex="-1">
      Security
    </button>
    <button class="tab"
            type="button"
            role="tab"
            aria-selected="false"
            aria-controls="panel-billing"
            id="tab-billing"
            tabindex="-1">
      Billing
    </button>
  </div>

  <section role="tabpanel" id="panel-general" aria-labelledby="tab-general" tabindex="-1" class="py">
    General content
  </section>
  <section role="tabpanel" id="panel-security" aria-labelledby="tab-security" tabindex="-1" hidden class="py">
    Security content
  </section>
  <section role="tabpanel" id="panel-billing" aria-labelledby="tab-billing" tabindex="-1" hidden class="py">
    Billing content
  </section>
</div>
<nav aria-label="Account sections">
  <ul class="tabs">
    <li><a class="tab primary" href="#account" aria-current="page">Profile</a></li>
    <li><a class="tab" href="#security">Security</a></li>
    <li><a class="tab" href="#billing">Billing</a></li>
  </ul>
</nav>