# An element with the attribute “tabindex” should not appear as a descendant of an element with the attribute “role=X”.

> Canonical HTML version: https://rocketvalidator.com/html-validation/an-element-with-the-attribute-tabindex-should-not-appear-as-a-descendant-of-an-element-with-the-attribute-role-x
> Attribution: Rocket Validator (https://rocketvalidator.com)
> License: CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)

An element with a `tabindex` attribute is nested inside an element whose ARIA role, such as `button`, `tab` or `checkbox`, describes a single control that should take focus as one unit.

ARIA in HTML gives an element with one of these roles the same content rules as the native control it imitates. A `<button>` can hold text and other phrasing content, but no interactive elements and no elements with a `tabindex` attribute. A `<div role="button">` follows the same rule.

The value of `tabindex` doesn't matter. With `tabindex="0"`, the inner element becomes a second tab stop inside the control. With `tabindex="-1"`, it stays out of the tab order, but a script or a mouse click can still focus it, so focus lands on part of the control instead of the control itself. Keyboard and screen reader users expect to reach the control once and activate it with Enter or Space. Most of these roles also have presentational children in WAI-ARIA, which means browsers shouldn't expose their descendants to assistive technologies as separate elements.

The validator checks descendants at any depth inside elements with `role` set to `button`, `checkbox`, `img`, `link`, `math`, `menuitem`, `menuitemcheckbox`, `menuitemradio`, `option`, `progressbar`, `radio`, `separator`, `slider`, `switch` or `tab`. The element with the role can have `tabindex` itself; the validator only flags its descendants.

It's a warning because the ARIA in HTML rule behind it is non-normative. Older validator builds reported it as an error, with "must not appear" in place of "should not appear". Inside a native `<button>` or `<a>`, a descendant with `tabindex` is still an error.

Remove `tabindex` from the descendant, and keep `tabindex="0"` on the element with the role. A native `<button>` is simpler, because it's focusable and responds to Enter and Space without extra attributes or scripts. Some carousel scripts give each slide `role="button"` and an inner `tabindex="-1"` element as a focus target. A slide with its own content, like an image and a caption, isn't a button, so remove `role="button"` from the slide and put a real `<button>` inside it for the action.

## Invalid example

```html
<div role="button" tabindex="0">
  <span class="label" tabindex="-1">Add to cart</span>
</div>
```

## Valid example

```html
<button type="button">
  <span class="label">Add to cart</span>
</button>
```

## Valid example keeping the role

```html
<div role="button" tabindex="0">
  <span class="label">Add to cart</span>
</div>
```
