Skip to content

IDs of focusable elements need to be unique

  • Rule: axe/duplicate-id-active
  • Checks: IDs of active elements must be unique
  • WCAG: 4.1.1
  • Fix class: mechanical: A fix needs no authored text or visual decision.
  • People who use a keyboard or a switch device instead of a mouse.
  • People who use a screen reader or a braille display, most of them blind.

Repeated controls share an id, such as a “Remove” button in each row

Section titled “Repeated controls share an id, such as a “Remove” button in each row”

Give each control its own id, built from the row’s key, or drop the id and use a class or data- attribute if it is only a hook.

<button type="button" id="remove-1042" data-order="1042">Remove order 1042</button>
<button type="button" id="remove-1043" data-order="1043">Remove order 1043</button>

Make the target id unique. getElementById() and same-page links find only the first match, so focus can land on the wrong control, or on one that is off screen or hidden.

A hidden copy of the control shares its id

Section titled “A hidden copy of the control shares its id”

Render one copy, or give each copy’s id a distinct suffix. Hidden elements still share the page’s ids.

The rule passes, but any script or link that used it to reach that control stops working. Check what refers to the id first.

The part of the fix that differs in React, in its syntax. The rest of the guidance holds.

A component gives its control a fixed id so a handler can find it

Section titled “A component gives its control a fixed id so a handler can find it”

Drop the id and keep a ref to the element instead: each instance of the component then reaches its own control. Where markup still needs the id, build it from useId.

import { useRef } from 'react';
function SearchField() {
const inputRef = useRef(null);
function clear() {
inputRef.current.value = '';
inputRef.current.focus();
}
return (
<>
<input ref={inputRef} type="search" aria-label="Search orders" />
<button type="button" onClick={clear}>
Clear search
</button>
</>
);
}

Keeping the fixed id and calling document.getElementById() in a handler

Section titled “Keeping the fixed id and calling document.getElementById() in a handler”

With the component on the page twice, the lookup finds the first copy, so focus or changes go to the wrong control.

axe-core’s documentation of the rule

CORA’s fix guidance adapts content from accessibility-agents, under the MIT License: see its notice.