useId
The useId hook is a React hook used for generating unique IDs that are stable across the server and client. It is primarily used to connect HTML elements for accessibility purposes, such as linking a <label> to an <input> or setting up aria-describedby.
Why useId?
Before useId, developers often resorted to generating random strings (e.g., Math.random()) or using global counters to create unique IDs. However, these approaches cause issues in Server-Side Rendering (SSR) environments like Next.js or Remix. When the server renders a random ID, it won't match the random ID generated by the client during hydration, leading to hydration mismatches and UI errors.
useId solves this by relying on the component tree's structure to generate consistent, globally unique IDs on both the server and client.
Basic Usage
To use useId, simply call it at the top level of your component. It takes no arguments and returns a unique string ID.
import { useId } from 'react';
export default function PasswordField() {
const passwordHintId = useId();
return (
<div>
<label>
Password:
<input
type="password"
aria-describedby={passwordHintId}
/>
</label>
<p id={passwordHintId}>
The password should contain at least 18 characters.
</p>
</div>
);
}
Connecting Multiple Elements
If a component needs multiple IDs, you don't need to call useId multiple times. Instead, call it once and append suffixes to the generated base ID:
import { useId } from 'react';
export default function UserForm() {
const id = useId();
return (
<form>
<div>
<label htmlFor={`${id}-firstName`}>First Name</label>
<input id={`${id}-firstName`} type="text" />
</div>
<div>
<label htmlFor={`${id}-lastName`}>Last Name</label>
<input id={`${id}-lastName`} type="text" />
</div>
</form>
);
}
Important Considerations
- DO NOT use
useIdfor list keys.useIdis not meant to generate keys for lists (<li key={...}>). List keys should be derived from your data (e.g., database IDs). - Format: The ID string generated by
useIdincludes the:token (e.g.,:r0:). This ensures the IDs don't collide with user-generated IDs, but it means they shouldn't be used in CSS selectors directly without escaping, such asdocument.querySelector.