aria-prohibited-children

Container roles must not own a child with a disallowed role

automaticWCAG 1.3.1 (A)confidence: mediumseverity: moderaterobust

Checks that every accessible-tree-owned child of a container role (list, listbox, menu, menubar, radiogroup, rowgroup, table, grid, treegrid, tablist, tree, row) has one of that role's allowed owned roles.

Applies to. Applies to elements with an explicit, valid role that is one of the container roles with a documented "required owned elements" entry (the same table aria-required-children uses).

Expectation. Every accessible-tree-owned descendant of the container (after pruning role="none"/"presentation" elements, and any "group"/ "rowgroup" wrapper the container's own required-owned set names, as transparent for owned-element matching per WAI-ARIA, regardless of whether "group"/"rowgroup" is itself in the container's own required-owned-roles set) has a role from that same required-owned set. Nothing else is a structurally valid direct child of a composite/container role, where "allowed" is the container's required-owned roles plus a small set of roles it may own without being required to (a separator between menu items, a caption on a grid). A roleless wrapper is descended into to reach the items a component library buries inside it, but once one is found there the rest of that wrapper's subtree is the item's own content and is not judged against the container.

What a finding reports.

  • containerRole: the container's role.
  • containerSelector: a selector for the container.
  • allowedOwnedRoles: the roles the container may own. Each item is a role name.
  • childRole (a child with a role): the child's role, which is not one of them; for a link, a button or another control focusable by itself, the role its element has (link, button). null on a child with no role.
  • attr (a child with no role, or one focusable by itself): what makes it a node of its own: the global aria-* attribute it carries, tabindex, or nativeFocusable when it can take focus without one (a link, a button).

These data.details fields help to read and reproduce a finding. Apart from reasonCode and the few fields Output schema names as stable, they are not a stable contract: a field may be renamed or dropped in a minor release, so don’t build on them.

Examples

pass
<ul role="menubar">
<li role="menuitem">File</li>
<li role="menuitem">Edit</li>
</ul>

Both owned children are roles menubar's spec allows.

fail
<div role="table">
<div role="row"><div role="cell">x</div></div>
<div role="button">Not a valid table child</div>
</div>

role="table" only allows row (or rowgroup) children; the button is a disallowed owned child.

View source