Hook useId
Genera una ID única y estable para atributos de accesibilidad que sea consistente entre servidor y cliente.
Busca en todas las páginas de la documentación
Genera una ID única y estable para atributos de accesibilidad que sea consistente entre servidor y cliente.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Tarjeta de referencia rápida - lista para copiar y pegar.
const id = useId();
// Usa para elementos de formulario accesibles
<label htmlFor={id}>Email</label>
<input id={id} type="email" />
// Deriva múltiples IDs de una
<label htmlFor={`${id}-first`}>First Name</label>
<input id={`${id}-first`} />
<label htmlFor={`${id}-last`}>Last Name</label>
<input id={`${id}-last`} />Cuándo usarlo: Necesitas una ID única para htmlFor, aria-labelledby, aria-describedby, o cualquier atributo DOM que requiera una ID - especialmente en SSR o componentes reutilizables.
"use client";
import { useId, useState } from "react";
interface TextFieldProps {
label: string;
helpText?: string;
}
export function TextField({ label, helpText }: TextFieldProps) {
const id = useId();
const helpId = `${id}-help`;
const [value, setValue] = useState("");
return (
<div className="space-y-1">
<label htmlFor={id} className="block text-sm font-medium">
{label}
</label>
<input
id={id}
value={value}
onChange={(e) => setValue(e.target.value)}
aria-describedby={helpText ? helpId : undefined}
className="border rounded px-3 py-2 w-full"
/>
{helpText && (
<p id={helpId} className="text-xs text-gray-500">
{helpText}
</p>
)}
</div>
);
}
export function SignupForm() {
return (
<form className="space-y-4 max-w-sm">
<TextField label="Email" helpText="We'll never share your email." />
<TextField label="Password" helpText="At least 8 characters." />
<TextField label="Username" />
</form>
);
}Lo que demuestra esto:
TextField obtiene su propia ID única de useId<label> a <input> mediante htmlFor y vincula el texto de ayuda mediante aria-describedbyuseId genera una ID basada en la posición del componente en el árbol de React: (por ejemplo, :r1:) para evitar colisiones con IDs definidas por el usuariouseId en el mismo componente producen diferentes IDs| Parámetro | Tipo | Descripción |
|---|---|---|
| (ninguno) | - | useId no toma parámetros |
| Retorno | Tipo | Descripción |
|---|---|---|
id | string | Cadena de ID única (por ejemplo, :r1:, :r2:) |
Listbox accesible:
function Listbox({ label, options }: ListboxProps) {
const id = useId();
const labelId = `${id}-label`;
const listId = `${id}-list`;
return (
<div>
<span id={labelId}>{label}</span>
<ul id={listId} role="listbox" aria-labelledby={labelId}>
{options.map((opt, i) => (
<li key={opt.value} id={`${id}-option-${i}`} role="option">
{opt.label}
</li>
))}
</ul>
</div>
);
}identifierPrefix personalizado para micro-frontends:
// En createRoot o hydrateRoot
const root = createRoot(container, {
identifierPrefix: "app1-",
});
// IDs generadas: ":app1-r1:", ":app1-r2:", etc.// useId siempre devuelve una cadena - no se necesita genérico
const id: string = useId();
// Al construir una librería de componentes, acepta una ID opcional para sobrescribir
interface InputProps {
id?: string;
label: string;
}
function Input({ id: propId, label }: InputProps) {
const generatedId = useId();
const inputId = propId ?? generatedId;
return (
<>
<label htmlFor={inputId}>{label}</label>
<input id={inputId} />
</>
);
}No uses para keys de lista - useId genera una única ID por llamada de hook, no por elemento de lista. No es adecuado para props key. Solución: Usa keys impulsadas por datos (item.id) o identificadores estables para keys de lista.
Las IDs contienen dos puntos - El formato de ID generado (:r1:) incluye dos puntos, que son válidos en atributos id HTML pero pueden causar problemas con selectores CSS como #\:r1\:. Solución: Usa selectores de atributo [id="value"] o escapa los dos puntos en CSS.
No se puede usar condicionalmente - Como todos los hooks, useId no se puede llamar dentro de condiciones o loops. Solución: Llama a useId al nivel superior y deriva sub-IDs con concatenación de cadenas.
Múltiples raíces sin prefijo - Dos raíces React separadas en la misma página pueden generar IDs en conflicto. Solución: Usa la opción identifierPrefix en createRoot o hydrateRoot.
| Alternativa | Usa Cuando | No Uses Cuando |
|---|---|---|
crypto.randomUUID() | App solo en cliente, sin SSR | SSR está involucrado - causa desincronización de hidratación |
| ID basada en contador | Fuera de React (funciones de utilidad) | Dentro de componentes - no es determinística entre servidor/cliente |
useRef con inicialización perezosa | Necesitas un valor aleatorio estable, no una ID basada en posición de árbol | Necesitas atributos de accesibilidad seguros para SSR |
Envolvimiento de <label> HTML | Label envuelve directamente el input, sin ID necesaria | Input y label están separados en el DOM |
¿Por qué no solo usar una ID aleatoria? Las IDs aleatorias generadas durante el renderizado difieren entre servidor y cliente, causando desincronización de hidratación y advertencias de React. useId resuelve esto derivando IDs de la posición del árbol de componentes.
useId deriva IDs de la posición del componente en el árbol de React, por lo que servidor y cliente producen la misma ID.useId siempre que SSR esté involucrado.useId genera una ID por llamada de hook, no por elemento de lista.htmlFor, aria-labelledby), no para props key.item.id) o identificadores estables para listas.const id = useId();
const nameId = `${id}-name`;
const emailId = `${id}-email`;
const helpId = `${id}-help`;useId.useId genera IDs como :r1: con dos puntos para evitar colisiones con IDs definidas por el usuario.id HTML pero deben escaparse en selectores CSS: #\:r1\:.[id="value"] en lugar de selectores de ID en CSS.:r1:, :r2:, etc.).identifierPrefix en createRoot o hydrateRoot para espaciar nombres de IDs.const root = createRoot(container, { identifierPrefix: "app1-" });
// IDs: ":app1-r1:", ":app1-r2:", etc.useId debe ser llamado al nivel superior de tu componente.// useId siempre devuelve cadena -- no se necesita genérico
const id: string = useId();string.interface InputProps {
id?: string;
label: string;
}
function Input({ id: propId, label }: InputProps) {
const generatedId = useId();
const inputId = propId ?? generatedId;
return (
<>
<label htmlFor={inputId}>{label}</label>
<input id={inputId} />
</>
);
}:r1:) es un detalle de implementación y puede cambiar entre versiones de React.useId() en el mismo componente devuelve una ID única.useIduseIdRevisado por Chris St. John·Última actualización: 16 jul 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥