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

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

An interactive element, like a link, a button or a form field, is nested inside an element whose ARIA role doesn't allow interactive descendants, such as `role="tab"`, `role="checkbox"` or `role="option"`.

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, but no links, buttons or form fields. An element with `role="tab"`, `role="checkbox"`, `role="radio"`, `role="option"` or `role="menuitem"` follows the same rule: phrasing content only, with no interactive content and no elements with a `tabindex` attribute inside it.

Most of these roles also have presentational children in WAI-ARIA, which means browsers shouldn't expose the element's descendants to assistive technologies. A screen reader can announce the tab and read the link inside it as plain text, with no way to reach it as a link. Keyboard users can also end up with two tab stops for what looks like one control.

The validator checks descendants of elements with `role` set to `button`, `checkbox`, `img`, `link`, `math`, `menuitem`, `menuitemcheckbox`, `menuitemradio`, `option`, `progressbar`, `radio`, `separator`, `slider`, `switch` or `tab`. It flags `<a>`, `<button>`, `<details>`, `<dialog>`, `<embed>`, `<iframe>`, `<label>`, `<select>`, `<textarea>` and every `<input>` except `type="hidden"`, plus `<audio>` and `<video>` with `controls` and `<img>` or `<object>` with `usemap`. An `<a>` is flagged even without `href`, and one with `href` gets a second warning, "The element "a" with the attribute "href" should not appear...". Both go away with the same fix.

The validator reports this as a warning because the ARIA in HTML section behind it is non-normative. Older validator builds reported it as an error, with "must not appear" in place of "should not appear".

Keep one interactive element per control. Either put the role on the interactive element itself, as in `<button role="tab">`, or drop the role and use the native element, like an `<input type="checkbox">` with its `<label>`. If the nested element is a separate action, move it out of the element with the role.

Accordions are a common source of `role="tab"` warnings. Older Bootstrap accordion examples put `role="tab"` on each panel heading, with a link inside it that opens the panel. An accordion is not a set of tabs, so remove `role="tablist"`, `role="tab"` and `role="tabpanel"`, and put a `<button>` with `aria-expanded` and `aria-controls` inside each heading.

## Invalid example

```html
<div role="tablist" aria-label="Billing">
  <div role="tab" id="tab-monthly" aria-selected="true" aria-controls="panel-monthly">
    <a href="#panel-monthly">Monthly</a>
  </div>
</div>
<div role="tabpanel" id="panel-monthly" aria-labelledby="tab-monthly">
  <p>Billed every month.</p>
</div>
```

## Valid example

```html
<div role="tablist" aria-label="Billing">
  <button type="button" role="tab" id="tab-monthly" aria-selected="true" aria-controls="panel-monthly">Monthly</button>
</div>
<div role="tabpanel" id="panel-monthly" aria-labelledby="tab-monthly">
  <p>Billed every month.</p>
</div>
```

## Valid example for an accordion

```html
<h2>
  <button type="button" aria-expanded="false" aria-controls="answer-shipping">How long does shipping take?</button>
</h2>
<div id="answer-shipping" hidden>
  <p>Orders ship within two business days.</p>
</div>
```

## Invalid example with a custom checkbox

```html
<div role="checkbox" aria-checked="false" tabindex="0">
  <input type="checkbox" id="newsletter">
  <label for="newsletter">Email me the newsletter</label>
</div>
```

## Valid example with a native checkbox

```html
<input type="checkbox" id="newsletter">
<label for="newsletter">Email me the newsletter</label>
```
