What does the useId() hook do?
What useId() does
useId()creates a unique, stable identifier (ID) that React guarantees is the same:
- on the server (during SSR),
- and on the client (during hydration).
This is needed for:
- linking form elements (e.g.
<label>and<input>), - generating
ids in lists where you can't use the index, - creating unique
aria-*attributes for accessibility (A11y), - generating identifiers in components that render many times.
Syntax
const id = useId();useId() returns a string (e.g. "react-aria123")
that is guaranteed unique within the whole application.
React guarantees:
- uniqueness within the component tree;
- stability across renders;
- a predictable match between the server and the client during SSR.
Usage example
Correctly linking a label and an input:
function NameField() {
const id = useId();
return (
<div>
<label htmlFor={id}>Name:</label>
<input id={id} type="text" />
</div>
);
}Why this matters:
-
If you used
Math.random()or a UUID, the server and the client would produce different values, and React would print a warning during hydration:javascriptWarning: Prop `id` did not match. Server: "a123" Client: "b456"
With useId(), this doesn't happen - React keeps the IDs in sync.
How React keeps IDs consistent
When rendering, React builds an ID from a deterministic prefix and counter, not a random number.
Example result:
id = react-aria123
id = react-aria124
id = react-aria125And these values will be the same:
- during server rendering (
renderToString()/renderToPipeableStream()), - during hydration on the client (
hydrateRoot()).
Example with several elements
function EmailForm() {
const emailId = useId();
const passwordId = useId();
return (
<form>
<label htmlFor={emailId}>Email</label>
<input id={emailId} type="email" />
<label htmlFor={passwordId}>Password</label>
<input id={passwordId} type="password" />
</form>
);
}Every call to useId() creates a new ID, but stable across renders.
Comparison with other approaches
| Method | Problem |
|---|---|
Math.random() | Different values on the server and client -> a hydration warning |
uuid() | A random result -> breaks SSR determinism |
| A counter in the component | Can get out of sync with conditional rendering |
useId() | Deterministic, unique, SSR-friendly |
Nested components
useId() also works well in nested components,
because React builds hierarchical prefixes
to avoid collisions between components.
Example:
function FormField({ label, children }) {
const id = useId();
return (
<div>
<label htmlFor={id}>{label}</label>
{React.cloneElement(children, { id })}
</div>
);
}
function Form() {
return (
<FormField label="Name">
<input type="text" />
</FormField>
);
}React will produce a unique, nested ID so there are no collisions:
react-aria1-1
react-aria1-2
react-aria2-1Using it together with CSS / aria
useId() is often used for accessibility attributes:
function Tooltip({ text, children }) {
const tooltipId = useId();
return (
<>
{React.cloneElement(children, { 'aria-describedby': tooltipId })}
<span id={tooltipId} role="tooltip">
{text}
</span>
</>
);
}Accessible, unique, and free of collisions even under SSR.
Limitations
useId()cannot be used inside loops / conditionals, otherwise the order of hook calls breaks (like any React hook).- It is not meant for dynamic unique keys in lists.
For
map()keys you still need to use unique identifiers from the data. - It doesn't suit generating global UUIDs - it's a tool only for stable IDs within the React tree.
Summary
useId()is a hook for generating unique, stable, and deterministic identifiers that match between the server and the client, which makes it invaluable for:
- SSR + Hydration,
- linking
label↔input,- working with aria attributes and accessibility,
- nested, repeating components.
In short:
| Property | Value |
|---|---|
| Returns | A unique ID string |
| Stability | Across renders and between server/client |
| SSR compatibility | Yes |
| Uniqueness in the tree | Guaranteed |
| Usable in a loop | No |
| Works with | React 18+ |
| Typical scenarios | Forms, aria, SSR, nested components |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.