The nested-interactive rule flags a control that contains another focusable control – a link inside a button, a button inside an element with role="button". Assistive technology treats the outer control as a single unit and cannot see what is inside it, so the inner control is announced wrongly or not at all. The fix is to put the controls side by side instead of one inside the other.
What the rule means
Some roles – button, link, checkbox, tab, menuitem, option and others – have "presentational children" in WAI-ARIA: whatever is inside them is flattened into their name. A link inside a button is therefore not a link to a screen reader; its text becomes part of the button's name, and the link itself cannot be reached or activated by browsing. Keyboard users may still tab onto it, and then hear something that makes no sense.
HTML says the same from the other direction: a <button> or an <a> must not contain interactive content. Browsers repair such markup in different ways, which is why the result is unpredictable.
Who is affected
Screen reader users, who hear one control where there are two and cannot reach the inner one. Voice-control users, who say the name of the link they see and activate the button around it. Keyboard users, who meet two Tab stops that do the same thing – or different things with no way to tell which is which.
Why the check fails
- Clickable cards built as
<div role="button">or<a>with a "More" link or a "Favourite" button inside. - Buttons with icon links, for example a "Download" button wrapping an
<a href>. - Accordion headers with
role="button"that contain a help link. - Table rows or list items turned into controls while they contain links.
- Component libraries that let you put anything into a button slot.
How to fix it
Make one element the control and keep other controls next to it, not inside it.
<!-- Before: a favourite button inside a clickable card -->
<div class="product-card" role="button" tabindex="0">
<h2>Desk lamp</h2>
<p>€49.00</p>
<button type="button" aria-label="Add desk lamp to favourites">♡</button>
</div>
<!-- After: the title is the link; the favourite button sits beside it -->
<div class="product-card">
<h2><a href="/products/desk-lamp/">Desk lamp</a></h2>
<p>€49.00</p>
<button type="button" aria-label="Add desk lamp to favourites">♡</button>
</div>
To keep the whole card clickable, stretch the link over the card with a positioned ::after and raise the button above it with position: relative; z-index: 1. The card looks and clicks the same; the markup no longer nests.
How to test it manually
- Tab through the component. Do you meet two stops for one visual control, or a stop inside another?
- With a screen reader, browse the component with the arrow keys. Can you reach and activate the inner control on its own?
- Check the accessibility tree: an outer control whose name contains the inner control's text is the tell-tale sign.
- Click every part of the card with the mouse and check each does what it says.
Related WCAG criterion
4.1.2 Name, Role, Value, Level A. Related: 2.1.1 Keyboard, because the inner control may be out of reach, and 2.5.3 Label in Name for voice users.
How Reviseberg reports it
Reviseberg runs nested-interactive on every crawled page. The issue list shows the rule with its severity, WCAG 4.1.2, the number of affected elements and pages, and the points a fix gets you back; the detail view shows the outer control's selector and HTML snippet. Card and teaser components repeat on listing pages, so the occurrence count is often high – and one component fix clears them all.