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.
Who it affects
Section titled “Who it affects”- 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.
How to fix it
Section titled “How to fix it”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>Script moves focus to a control by its id
Section titled “Script moves focus to a control by its id”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.
Fixes that fail
Section titled “Fixes that fail”Deleting the id from the second control
Section titled “Deleting the id from the second control”The rule passes, but any script or link that used it to reach that control stops working. Check what refers to the id first.
In React
Section titled “In React”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> </> );}Fixes that fail in React
Section titled “Fixes that fail in React”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.
More on the rule
Section titled “More on the rule”axe-core’s documentation of the rule
CORA’s fix guidance adapts content from accessibility-agents, under the MIT License: see its notice.