Suggest an editImprove this articleRefine the answer for “What does the useId() hook do?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**`useId()`** creates a unique, stable identifier that React guarantees is the same both on the server (during SSR) and on the client (during hydration). **Key point:** this is needed for linking form elements (`label` and `input`), generating `aria-*` attributes for accessibility, and any other case where `Math.random()` or `uuid()` would produce different values on the server and client and break hydration.Shown above the full answer for quick recall.Answer (EN)Image## 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 `id`s 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 ```javascript 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`: ```javascript 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**: ```javascript Warning: 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: ```javascript id = react-aria123 id = react-aria124 id = react-aria125 ``` And these values will be **the same**: - during server rendering (`renderToString()` / `renderToPipeableStream()`), - during hydration on the client (`hydrateRoot()`). --- ## Example with several elements ```javascript 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: ```javascript 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: ```javascript react-aria1-1 react-aria1-2 react-aria2-1 ``` --- ## Using it together with CSS / aria `useId()` is often used for accessibility attributes: ```javascript 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 1. `useId()` cannot be used **inside loops / conditionals**, otherwise the order of hook calls breaks (like any React hook). 2. It is not meant for **dynamic unique keys** in lists. For `map()` keys you still need to use unique identifiers from the data. 3. 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 |For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.