How to fix interactive controls nested inside each other?
nested-interactive page
The issue
A control inside another control works for a mouse and fails for almost everyone else. A screen reader may announce only the outer link and fold the inner button into its text, so the button’s action can’t be found. Keyboard focus can stop twice on what looks like one control, and pressing Enter may trigger the outer action instead of the one the user meant.
The cause is usually a card pattern: the whole card is wrapped in a link, then a “Save” button or a second link is added inside it. HTML doesn’t allow interactive content inside <a> or <button>, and browsers and assistive technology each resolve the conflict differently. WCAG 4.1.2 requires every control to expose its name and role, which a control buried in another one can’t.
Scope
Every visible interactive element is checked: links with an href, buttons, inputs other than type="hidden", selects, textareas, <summary>, anything with a tabindex other than -1, and elements with a control role such as button, link, checkbox, tab, option or slider. The outer element is reported when it contains any of these. A control inside it counts even when that inner control is hidden.
How to check you have it
- In probeo: the page reports
nested-interactive, “Interactive controls must not be nested”, as serious, under WCAG 4.1.2. The detail names the nested elements, such as<button>. - By hand: in DevTools, inspect each card or clickable row and look for a
<button>,<input>or second<a>inside an<a>or<button>. - With a tool: axe DevTools has a rule with the same name. Tabbing through the page also shows it: focus lands on the card and then again inside it.
The fix
Move the inner control out of the outer one, so every control stands on its own.
For a card, make the heading’s link the card’s main action and let it cover the card with CSS, then place the other buttons beside it rather than inside it. The whole card stays clickable, and each control keeps its own name and focus stop.
<article class="card">
<h3><a href="/plans/pro/" class="card-link">Pro plan</a></h3>
<p>For teams of up to 20.</p>
<button type="button">Save</button>
</article>.card { position: relative; }
.card-link::after { content: ""; position: absolute; inset: 0; }
.card button { position: relative; z-index: 1; }Done when: no link, button or other control contains another, and the check above comes back clean.
Do not
- Do not wrap a whole card in a link that also holds buttons or other links.
- Do not give a wrapper
tabindex="0"to make the whole card focusable when it already contains controls. - Do not rely on a click handler on the card in place of a real link.
FAQ
Why does a card with one link and one button fail?
Because the button sits inside the link. Each works on its own, but nested, the link’s name swallows the button’s text and the button’s role can be lost. Make them siblings.
Does a link inside a summary element count?
Yes. Probeo treats <summary> as the control for its <details>, so a link inside <summary> is nested. Links in the rest of the <details> content are fine.
Is a hidden control inside a link still a problem?
Probeo still reports it. A control that is hidden now is usually shown later by a script, and then the nesting is real. Move it out rather than hiding it.
Does tabindex="-1" on the inner control fix it?
Not for links and buttons: they stay controls whatever their tabindex. It removes them from the tab order, which makes the problem harder to see without solving it.
Which product detects this
Probeo checks this on every page of your site as part of Site Clarity. This page explains one instance; the product tells you every page that has it.