The useId Hook returns a unique ID string that stays stable for a given component instance. You pass that ID to accessibility attributes such as aria-describedby, so a label and its input stay connected even when the component renders several times on one page.
What useId returns
Call useId at the top level of your component. It takes no arguments and returns a string you can attach to id attributes.
| Part | Behavior |
|---|---|
| Arguments | None. |
| Return value | A unique ID string for this component instance. |
| Stability | Stable across renders for the same mounted instance. |
The ID is not a plain counter. React builds it from the component's position in the tree, which keeps server and client output identical when the two trees match.
Why an incrementing counter is not enough
A global counter like nextId++ looks simpler, but it breaks under server rendering. The order in which client components hydrate may not match the order the server emitted HTML, so the counter produces different IDs on each side. useId avoids that mismatch because it derives the ID from the parent path of the component.
Why hardcoded IDs fail
A hardcoded id attribute works once, then breaks the moment the component renders twice. Two elements with the same id confuse both browsers and assistive technology. Hardcoding also forces every consumer to coordinate on the same string, which breaks reuse.
import { useId } from "react";
function PasswordField() {
const passwordHintId = useId();
return (
<>
<input type="password" aria-label="Password" aria-describedby={passwordHintId} />
<p id={passwordHintId}>Use at least 18 characters.</p>
</>
);
}The input points to the hint through aria-describedby, and the hint carries the same generated id. If PasswordField renders twice, each copy gets its own ID, so the two inputs stay paired with the right hint. A screen reader reads the hint when the input receives focus.
Generate several IDs from one prefix
One call to useId can serve several related elements by adding suffixes.
import { useId } from "react";
function NameFields() {
const id = useId();
return (
<>
<label htmlFor={`${id}-first`}>First name</label>
<input id={`${id}-first`} type="text" />
<label htmlFor={`${id}-last`}>Last name</label>
<input id={`${id}-last`} type="text" />
</>
);
}The shared base keeps the two fields unique while each label still pairs with its own input. This avoids a separate useId call for every element.
What useId is not for
useId is for accessibility attributes, not for general identity. Do not generate list keys from it, because keys should come from your data. Do not generate cache keys from it, because the ID may change during rendering.
What to learn next
Accessible IDs pair naturally with live announcements. Continue with how to announce dynamic updates to screen readers, and see how to make clickable elements accessible for more label and focus patterns.
Rune AI
Key Insights
- useId returns a unique ID string and takes no arguments.
- Pass the ID to attributes like aria-describedby and htmlFor.
- One call can serve several elements using suffixes.
- Do not use useId for list keys or cache keys.
- Server and client must render identical trees for IDs to match.
Frequently Asked Questions
What does useId return?
Can I use useId for list keys?
Does useId work with server rendering?
Conclusion
useId generates stable, unique ID strings for connecting related elements through accessibility attributes. Use one ID per component instance, or a shared prefix for several related elements.
More in this topic
How to Build a Dropdown Menu in React
Build a React dropdown menu with the ARIA menu button pattern. Handle open and close, keyboard arrows, and clicks outside the menu.
How to Animate React Components with Motion
Animate React components with the Motion library. Set up motion, add enter, hover, and exit animations, and respect reduced motion.
Headless UI Components Explained: Logic Without Locked Styling
Understand headless UI components and how libraries like Radix give you unstyled, accessible behavior that you style yourself.