This browser warning occurs when multiple DOM elements share the same id attribute, violating HTML uniqueness requirements. Duplicate IDs break accessibility features, cause unpredictable JavaScript behavior, and can lead to incorrect form associations.
This warning is issued by the browser when it detects multiple HTML elements on the same page using the same `id` attribute value. In HTML, the `id` attribute must be unique across the entire document - each ID can only appear once. In React applications, this commonly happens when components with hardcoded IDs are reused multiple times on the same page. For example, rendering a form component twice will create two inputs with the same ID, triggering this warning. While the page may still render, duplicate IDs cause serious problems: screen readers may read the wrong label text, JavaScript selectors like `document.getElementById()` will only find the first element, and form labels may point to the wrong input fields. These issues severely impact accessibility and user experience.
Open your browser's developer console and look for the warning message. It will specify which ID is duplicated:
[DOM] Found 2 elements with non-unique id #email-inputSearch your codebase for that ID to find all components using it:
# Find all occurrences of the duplicate ID
grep -r 'id="email-input"' src/Identify which component is being rendered multiple times on the same page.
Replace hardcoded IDs with React's useId hook, which generates unique IDs automatically:
import { useId } from 'react';
function FormField({ label }: { label: string }) {
const id = useId();
return (
<div>
<label htmlFor={id}>{label}</label>
<input id={id} type="text" />
</div>
);
}
// Safe to render multiple times
<FormField label="First Name" />
<FormField label="Last Name" />The useId hook ensures each component instance gets a unique ID, even when rendered multiple times or server-side rendered.
When rendering lists, use useId with a suffix for each item:
import { useId } from 'react';
function TaskList({ tasks }: { tasks: string[] }) {
const baseId = useId();
return (
<ul>
{tasks.map((task, index) => (
<li key={index}>
<input
type="checkbox"
id={`${baseId}-${index}`}
/>
<label htmlFor={`${baseId}-${index}`}>
{task}
</label>
</li>
))}
</ul>
);
}This creates IDs like :r1:-0, :r1:-1, etc., ensuring uniqueness across all items.
For components that need external ID control, accept the ID as a prop:
interface InputFieldProps {
id?: string;
label: string;
}
function InputField({ id, label }: InputFieldProps) {
const generatedId = useId();
const finalId = id || generatedId;
return (
<div>
<label htmlFor={finalId}>{label}</label>
<input id={finalId} type="text" />
</div>
);
}
// Use with custom ID
<InputField id="email" label="Email" />
// Or let it generate one automatically
<InputField label="Name" />This provides flexibility while maintaining uniqueness by default.
After implementing unique IDs, verify the fixes:
1. Clear browser console warnings
2. Test form label clicking - each label should focus its corresponding input
3. Use browser DevTools to inspect ID attributes and confirm uniqueness
4. Run accessibility testing tools:
# Using axe-core or similar
npm run test:a11y5. Test with a screen reader to ensure labels are announced correctly
All duplicate ID warnings should be eliminated and form associations should work properly.
Why not use Math.random() or Date.now()?
While Math.random() or Date.now() seem like quick solutions for unique IDs, they break server-side rendering (SSR) and hydration. The server generates one set of random IDs during SSR, but the client generates different IDs during hydration, causing React hydration mismatches and forcing re-renders. The useId hook solves this by generating deterministic IDs that match between server and client.
useId for multiple related elements
When a single component needs multiple unique IDs (e.g., input, error message, description), share a common prefix:
const id = useId();
<input id={id} aria-describedby={`${id}-description`} aria-errormessage={`${id}-error`} />
<div id={`${id}-description`}>Enter your email</div>
<div id={`${id}-error`}>Invalid email format</div>Third-party component conflicts
Some third-party libraries generate their own IDs. If you use multiple instances, wrap them in a component that manages ID collisions, or check the library's documentation for ID customization props.
Legacy class components
If you're using class components (pre-React 18), use a counter or UUID library instead of useId:
let globalIdCounter = 0;
class FormField extends React.Component {
private id = `field-${globalIdCounter++}`;
render() {
return <input id={this.id} />;
}
}However, migrating to function components with useId is strongly recommended for better SSR compatibility.
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite