Skip to main content
HTML Validation

An element with the attribute “tabindex” must not appear as a descendant of an element with the attribute “role=button”.

About This HTML Issue

When an element has role="button", assistive technologies treat it as a single interactive control — just like a native <button>. Users expect to tab to it once, and then activate it with Enter or Space. If a focusable descendant (an element with tabindex) exists inside that button, it creates a second tab stop within what should be a single control. This breaks the expected interaction model and confuses both keyboard users and screen readers.

The WAI-ARIA specification explicitly states that certain roles, including button, must not contain interactive or focusable descendants. This is because a button is an atomic widget — it represents one action and should receive focus as a single unit. When a screen reader encounters a role="button" element, it announces it as a button and expects the user to interact with it directly. A nested focusable element disrupts this by creating an ambiguous focus target: should the user interact with the outer button or the inner focusable element?

This issue commonly arises when developers wrap inline elements like <span> or <a> with tabindex inside a <div role="button">, often to style parts of the button differently or to add click handlers. The correct approach is to ensure only the outermost button-like element is focusable.

How to fix it

  1. Use a native <button> element. This is always the best solution. Native buttons handle focus, keyboard interaction (Enter and Space key activation), and accessibility announcements automatically — no role or tabindex needed.

  2. Move tabindex to the role="button" container. If you must use role="button" (for example, when a <div> needs to behave as a button due to design constraints), place tabindex="0" on the container itself and remove tabindex from all descendants.

  3. Remove tabindex from descendants. If the inner element doesn’t actually need to be independently focusable, simply remove the tabindex attribute from it.

When using role="button" on a non-interactive element, remember you also need to implement keyboard event handlers for Enter and Space to fully replicate native button behavior.

Examples

Incorrect: focusable descendant inside role="button"

<div role="button">
  <span tabindex="0">Click me</span>
</div>

The <span> with tabindex="0" creates a focusable element inside the role="button" container, which violates the ARIA authoring rules.

Incorrect: anchor element inside role="button"

<div role="button" tabindex="0">
  <a href="/action" tabindex="0">Perform action</a>
</div>

Even though the container itself is focusable, the nested <a> with tabindex is also focusable, creating two tab stops for what should be a single control.

Correct: use a native <button> element

<button>Click me</button>

A native <button> handles focus, keyboard events, and accessibility semantics out of the box with no additional attributes.

Correct: move tabindex to the role="button" container

<div role="button" tabindex="0">
  <span>Click me</span>
</div>

The tabindex="0" is on the role="button" element itself, and the inner <span> is not independently focusable.

Correct: native button with styled inner content

<button>
  <span class="icon"></span>
  <span class="label">Favorite</span>
</button>

You can still use inner elements for styling purposes inside a <button> — just don’t add tabindex to them. The button manages focus as a single unit, and screen readers announce the combined text content.

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.