Skip to main content
HTML Validation

An element with “role=tab” must be contained in, or owned by, an element with “role=tablist”.

About This HTML Issue

The WAI-ARIA specification defines a strict ownership model for tab-related roles. An element with role="tab" controls the visibility of an associated role="tabpanel" element, and tabs are expected to be grouped within a tablist. This relationship is how assistive technologies like screen readers understand and communicate the tab interface pattern to users — for example, announcing “tab 2 of 4” when focus moves between tabs.

When a tab is not contained in or owned by a tablist, screen readers cannot determine how many tabs exist in the group, which tab is currently selected, or how to navigate between them. This fundamentally breaks the accessibility of the tab interface, making it confusing or unusable for people who rely on assistive technologies.

There are two ways to establish the required relationship:

  1. Direct containment: Place the role="tab" elements as direct children of the role="tablist" element. This is the most common and straightforward approach.
  2. Using aria-owns: If the DOM structure prevents direct nesting, add aria-owns to the tablist element with a space-separated list of id values referencing each tab. This tells assistive technologies that the tablist owns those tabs even though they aren’t direct children in the DOM.

Examples

Incorrect: tab outside of a tablist

In this example, the role="tab" buttons are siblings of the tablist rather than children of it, which triggers the validation error.

<div class="tabs">
  <div role="tablist" aria-label="Sample Tabs"></div>
  <button role="tab" aria-selected="true" aria-controls="panel-1" id="tab-1">
    First Tab
  </button>
  <button role="tab" aria-selected="false" aria-controls="panel-2" id="tab-2">
    Second Tab
  </button>
</div>

Correct: tabs as direct children of tablist

The simplest fix is to place the role="tab" elements directly inside the role="tablist" element.

<div class="tabs">
  <div role="tablist" aria-label="Sample Tabs">
    <button role="tab" aria-selected="true" aria-controls="panel-1" id="tab-1" tabindex="0">
      First Tab
    </button>
    <button role="tab" aria-selected="false" aria-controls="panel-2" id="tab-2" tabindex="-1">
      Second Tab
    </button>
  </div>
  <div id="panel-1" role="tabpanel" tabindex="0" aria-labelledby="tab-1">
    <p>Content for the first panel</p>
  </div>
  <div id="panel-2" role="tabpanel" tabindex="0" aria-labelledby="tab-2" hidden>
    <p>Content for the second panel</p>
  </div>
</div>

Correct: using aria-owns when DOM nesting isn’t possible

If your layout or framework makes it difficult to nest the tabs directly inside the tablist, you can use aria-owns to establish the relationship programmatically.

<div class="tabs">
  <div role="tablist" aria-label="Sample Tabs" aria-owns="tab-1 tab-2"></div>
  <div class="tab-wrapper">
    <button role="tab" aria-selected="true" aria-controls="panel-1" id="tab-1" tabindex="0">
      First Tab
    </button>
    <button role="tab" aria-selected="false" aria-controls="panel-2" id="tab-2" tabindex="-1">
      Second Tab
    </button>
  </div>
  <div id="panel-1" role="tabpanel" tabindex="0" aria-labelledby="tab-1">
    <p>Content for the first panel</p>
  </div>
  <div id="panel-2" role="tabpanel" tabindex="0" aria-labelledby="tab-2" hidden>
    <p>Content for the second panel</p>
  </div>
</div>

Additional notes

  • Each role="tab" element should use aria-selected to indicate which tab is active ("true") and which are not ("false").
  • Use aria-controls on each tab to reference the id of its associated tabpanel.
  • Use aria-labelledby on each tabpanel to point back to its controlling tab.
  • Set tabindex="0" on the active tab and tabindex="-1" on inactive tabs to support keyboard navigation with arrow keys within the tablist.
  • Always include an aria-label or aria-labelledby on the tablist to give it an accessible name.

Find issues like this automatically

Rocket Validator scans thousands of pages in seconds, detecting HTML issues across your entire site.

Help us improve our guides

Was this guide helpful?

Ready to validate your sites?
Start your free trial today.