Field
Etiquetas, descripciones y errores conectados a su control, con estados de validación y diseños para formularios.
pnpm dlx shadcn@latest add https://hextaui.com/r/field.jsonAñade el componente, los tokens del tema de HextaUI y los componentes de HextaUI de los que depende.
Añade los tokens del tema a tu CSS global, si aún no lo has hecho.
Instala las dependencias.
pnpm add @base-ui/react @tabler/icons-react class-variance-authority cnCopia y pega el siguiente código en tu proyecto.
components/ui/field.tsx components/ui/input.tsx components/ui/number-flow.tsx components/ui/separator.tsx lib/motion.ts Actualiza las rutas de importación para que coincidan con la configuración de tu proyecto.
Pon cualquier control de HextaUI dentro de un <Field /> y se etiqueta, describe y valida automáticamente. No hace falta conectar id, htmlFor ni aria-describedby a mano.
Un control con su etiqueta, texto de ayuda y validación.
Un switch o checkbox con su texto al lado.
Una etiqueta que envuelve un campo completo, de modo que la tarjeta es el objetivo del clic.
Campos relacionados, con espaciado uniforme.
Un grupo de campos con título, o un grupo de radio o checkbox con un elemento por opción.
Input
Una etiqueta, un control y una descripción. Hacer clic en la etiqueta da foco al input, y los lectores de pantalla leen la descripción después de la etiqueta.
Validación
Las restricciones nativas como required y minLength se comprueban al perder el foco. Dale a cada <FieldError /> un match para redactar el mensaje según el problema. Un campo obligatorio vacío solo se marca después de haberse editado, así que tabular más allá de él no avisa a gritos.
Validación personalizada
Pasa validate para comprobar cualquier cosa, incluidas búsquedas asíncronas. Devuelve un mensaje para fallar o nada para aprobar. Con validationMode="onChange" y validationDebounceTime, se ejecuta mientras escribes sin dispararse en cada tecla. Prueba con “ada”.
Obligatorio y opcional
Define indicator en un FieldGroup, FieldSet o Field y cada etiqueta de su interior se marca a partir del atributo required de su control. "optional" marca los campos que se pueden omitir, lo que resulta más tranquilo cuando la mayoría de los campos son obligatorios. "required" añade un asterisco. La marca está oculta para los lectores de pantalla porque el control ya lo anuncia.
Estado
<FieldStatus /> dibuja una marca cuando un campo editado supera la validación, y muestra un icono de alerta mientras falla. Sigue el validationMode del campo, así que nunca juzga un campo antes de que se haya ejecutado la validación.
Contador de caracteres
<FieldCounter /> encuentra el control de texto de su campo y cuenta respecto a su maxLength. Solo escucha, así que escribir nunca se ralentiza ni se modifica.
Errores de una librería de formularios o del servidor
Pasa invalid al campo y un array errors a <FieldError />. Acepta la forma { message } que devuelven React Hook Form y la mayoría de las librerías de esquemas. Los duplicados se descartan y varios mensajes se convierten en una lista. Cuando los mensajes cambian, los nuevos aparecen con un fundido y la altura se ajusta suavemente, así que nada de lo que hay debajo salta. Envía vacío y luego corrige una regla a la vez.
Casillas de verificación
Usa orientation="horizontal" para poner el checkbox junto a su etiqueta. Dentro de un <FieldSet />, la leyenda nombra todo el grupo.
Tarjetas de elección
Envuelve un campo completo en <FieldLabel /> para que la tarjeta sea el objetivo del clic. Usa <FieldTitle /> dentro, ya que las etiquetas no se pueden anidar. La tarjeta se tiñe al marcarse y muestra el anillo de foco cuando su checkbox recibe foco.
Fieldset
<FieldSet /> agrupa campos relacionados bajo un <FieldLegend />, que se convierte en el nombre accesible del grupo. Coloca los campos uno al lado del otro con una cuadrícula simple.
Responsive
orientation="responsive" apila la etiqueta y el control en espacios estrechos y los pone lado a lado cuando el <FieldGroup /> que los rodea es lo bastante ancho. Responde al ancho del grupo, no al de la ventana.
Deshabilitado
Deshabilitar un <FieldSet /> deshabilita todos los campos y controles de su interior. Pasa disabled a un solo <Field /> para deshabilitar únicamente ese.
Contenido largo
Las etiquetas, descripciones y errores se ajustan dentro de formularios estrechos, incluidas las cadenas sin espacios, y nunca ensanchan el diseño.
De derecha a izquierda
El texto, la posición del checkbox y las listas de errores siguen la dirección de lectura.
- La etiqueta, la descripción y los errores visibles se vinculan al control por ti, así que los lectores de pantalla anuncian los tres cuando recibe foco.
- Los controles no válidos reciben
aria-invalid, que también dibuja su anillo de error. - Los errores no son regiones activas. Se leen cuando el control recibe foco, así que validar al cambiar no interrumpe la escritura. Al enviar, mueve el foco al primer campo no válido.
- Los errores crecen y aparecen con un fundido en su sitio en lugar de empujar el contenido hacia abajo. Con movimiento reducido, aparecen sin animación.
Construido sobre el field y el fieldset de Base UI. Cada parte acepta las props del elemento o la primitiva que renderiza.
| Prop | Tipo | Predeterminado |
|---|---|---|
orientation | "vertical" | "horizontal" | "responsive" | "vertical" |
indicatorMarca la etiqueta a partir del atributo required del control. Se hereda de FieldGroup o FieldSet. | "required" | "optional" | null | – |
nameIdentifica el campo cuando se envía el formulario. | string | – |
validateDevuelve uno o más mensajes para fallar, o nada para aprobar. Se admite async. | (value, formValues) => string | string[] | null | Promise<…> | – |
validationMode | "onSubmit" | "onBlur" | "onChange" | "onSubmit" |
validationDebounceTimeMilisegundos de espera entre validaciones de onChange. | number | 0 |
invalidDefínelo desde una librería de formularios o una respuesta del servidor. | boolean | – |
disabled | boolean | false |
dirty | boolean | – |
touched | boolean | – |
actionsRefValida el campo de forma imperativa. | RefObject<{ validate: () => void }> | – |
render | ReactElement | (props, state) => ReactElement | <div> |
| Atributo | Descripción |
|---|---|
data-slot="field" | Selecciona los campos en CSS. |
data-orientation | La orientación actual. |
data-disabled | Presente cuando el campo está deshabilitado. |
data-valid | Presente cuando el campo es válido. |
data-invalid | Presente cuando el campo no es válido. |
data-dirty | Presente una vez que el valor ha cambiado respecto al inicial. |
data-touched | Presente una vez que el control ha recibido foco y lo ha perdido. |
data-filled | Presente cuando el control tiene un valor. |
data-focused | Presente mientras el control tiene foco. |
| Prop | Tipo | Predeterminado |
|---|---|---|
nativeLabelPonlo en false cuando render cambie la etiqueta por un elemento que no sea una etiqueta. | boolean | true |
optionalTextTexto que se muestra con indicator="optional". | ReactNode | "Optional" |
render | ReactElement | (props, state) => ReactElement | <label> |
| Atributo | Descripción |
|---|---|
data-slot="field-label" | Selecciona las etiquetas en CSS. Fuera de un campo renderiza una etiqueta simple, que es como funcionan las tarjetas de elección. |
data-disabled | Presente cuando el campo está deshabilitado. |
data-valid | Presente cuando el campo es válido. |
data-invalid | Presente cuando el campo no es válido. |
data-dirty | Presente una vez que el valor ha cambiado respecto al inicial. |
data-touched | Presente una vez que el control ha recibido foco y lo ha perdido. |
data-filled | Presente cuando el control tiene un valor. |
data-focused | Presente mientras el control tiene foco. |
Un icono que refleja la validez del campo. Es decorativo, ya que el mensaje de error lleva el significado.
| Atributo | Descripción |
|---|---|
data-slot="field-status" | Selecciona el icono de estado en CSS. |
| Prop | Tipo | Predeterminado |
|---|---|---|
threshold | number | 10% of maxLength, at most 20 |
announcementMensaje para lectores de pantalla cuando el recuento cruza el umbral o llega al límite. | (remaining: number) => string | – |
| Atributo | Descripción |
|---|---|
data-slot="field-counter" | Selecciona el contador en CSS. |
data-state="near" | "limit" | Presente dentro del umbral y en el límite. |
| Prop | Tipo | Predeterminado |
|---|---|---|
render | ReactElement | (props, state) => ReactElement | <p> |
| Atributo | Descripción |
|---|---|
data-slot="field-description" | Selecciona las descripciones en CSS. |
data-disabled | Presente cuando el campo está deshabilitado. |
data-valid | Presente cuando el campo es válido. |
data-invalid | Presente cuando el campo no es válido. |
data-dirty | Presente una vez que el valor ha cambiado respecto al inicial. |
data-touched | Presente una vez que el control ha recibido foco y lo ha perdido. |
data-filled | Presente cuando el control tiene un valor. |
data-focused | Presente mientras el control tiene foco. |
| Prop | Tipo | Predeterminado |
|---|---|---|
matchSe muestra solo para este problema de validez. true lo muestra siempre. | boolean | "valueMissing" | "typeMismatch" | "tooShort" | "tooLong" | "patternMismatch" | "rangeOverflow" | "rangeUnderflow" | "stepMismatch" | "badInput" | "customError" | "valid" | – |
errorsErrores de una librería de formularios o del servidor. Se muestran cuando la lista tiene un mensaje. | Array<{ message?: string } | undefined> | – |
childrenPor defecto es el mensaje de validación. | ReactNode | – |
render | ReactElement | (props, state) => ReactElement | <div> |
| Atributo | Descripción |
|---|---|
data-slot="field-error" | Selecciona los errores en CSS. |
data-starting-style | Presente mientras el error crece al aparecer. |
data-ending-style | Presente mientras el error se colapsa. |
data-disabled | Presente cuando el campo está deshabilitado. |
data-valid | Presente cuando el campo es válido. |
data-invalid | Presente cuando el campo no es válido. |
data-dirty | Presente una vez que el valor ha cambiado respecto al inicial. |
data-touched | Presente una vez que el control ha recibido foco y lo ha perdido. |
data-filled | Presente cuando el control tiene un valor. |
data-focused | Presente mientras el control tiene foco. |
Apila una etiqueta, una descripción y un error junto a un control en un campo horizontal.
| Prop | Tipo | Predeterminado |
|---|---|---|
render | ReactElement | (props, state) => ReactElement | <div> |
Un título con estilo de etiqueta para el contenido dentro de un <FieldLabel />, como las tarjetas de elección.
| Prop | Tipo | Predeterminado |
|---|---|---|
render | ReactElement | (props, state) => ReactElement | <div> |
Separa los campos y es el contenedor que miden los campos responsive.
| Prop | Tipo | Predeterminado |
|---|---|---|
indicatorSe aplica a todos los campos de su interior. | "required" | "optional" | null | – |
render | ReactElement | (props, state) => ReactElement | <div> |
| Prop | Tipo | Predeterminado |
|---|---|---|
indicatorSe aplica a todos los campos de su interior. | "required" | "optional" | null | – |
disabledDeshabilita todos los campos de su interior. | boolean | false |
render | ReactElement | (props, state) => ReactElement | <fieldset> |
| Atributo | Descripción |
|---|---|
data-slot="field-set" | Selecciona los fieldsets en CSS. |
data-disabled | Presente cuando el fieldset está deshabilitado. |
| Prop | Tipo | Predeterminado |
|---|---|---|
variantlabel coincide con el tamaño de una etiqueta de campo. | "legend" | "label" | "legend" |
render | ReactElement | (props, state) => ReactElement | <div> |
| Atributo | Descripción |
|---|---|
data-slot="field-legend" | Selecciona las leyendas en CSS. |
data-variant | La variante actual. |
Un <Separator /> con el espaciado adecuado para formularios, que acepta todas sus props.
| Prop | Tipo | Predeterminado |
|---|---|---|
childrenTexto opcional que se muestra en medio de la línea. | ReactNode | – |
alignDónde se sitúa el texto a lo largo de la línea. | "start" | "center" | "end" | "center" |
decorativeOculta una línea simple a los lectores de pantalla cuando es solo visual. | boolean | false |
render | ReactElement | (props, state) => ReactElement | <div> |
| Atributo | Descripción |
|---|---|
data-slot="field-separator" | Selecciona los separadores de campo en CSS. |
data-content | Presente cuando el separador tiene texto. |
data-slot="separator-label" | El elemento que envuelve el texto. |
Envuelve un checkbox o radio y su etiqueta dentro de un grupo, para que cada elemento se pueda deshabilitar por separado.
| Prop | Tipo | Predeterminado |
|---|---|---|
disabled | boolean | false |
render | ReactElement | (props, state) => ReactElement | <div> |
Renderiza cualquier cosa a partir del estado de validez del campo, por ejemplo un medidor de seguridad o un contador de caracteres.
| Prop | Tipo | Predeterminado |
|---|---|---|
children | (state: { validity, errors, error, value }) => ReactNode | – |
- InputUn campo de texto con tres tamaños, estados inválido y de solo lectura, estilos de validación nativos y una fuente táctil de 16px para que los móviles nunca hagan zoom.
- MotionLas curvas de easing, duraciones y la comprobación de movimiento reducido con las que se anima cada componente, además de hooks para transformaciones de tamaño y resaltados deslizantes.
- SeparatorUna línea fina que divide el contenido horizontal o verticalmente, con una etiqueta opcional y un modo decorativo para líneas puramente visuales.
- useComposedRefMantiene una ref a tu propio elemento y sigue reenviándola a la ref que haya pasado el padre.
- useMergedRefCombina cualquier cantidad de refs de callback y de objeto en una sola, con la limpieza de refs de React 19 para cada una.
- CalendarUna cuadrícula de fechas para selección única, de rango y múltiple, con meses deslizantes, vistas previas de rango y días de tamaño táctil.
Usado en bloques
Bloques que se construyen sobre Field.
- API keysLa página de claves de API de un producto de IA, como las consolas de OpenAI y Anthropic. Crea claves con permisos acotados y caducidad, ve el secreto una sola vez con una copia que lo confirma, revoca con deshacer, renombra en el sitio, rota con un periodo de gracia y consulta el uso por clave.
- BillingPlan y uso para un producto de IA, al estilo de Cursor, Claude y Vercel. Un medidor de uso dividido por modelo que proyecta el final del ciclo y avisa antes de que se agoten los créditos, un gráfico diario por el que puedes desplazarte, un límite de gasto con alertas que puedes previsualizar en el medidor, cambios de plan con prorrateo exacto, un formulario de tarjeta con validación real y facturas descargables en PDF.
- ModelsLa página Modelos de los ajustes de un producto de IA. Un modelo predeterminado con su contexto, velocidad y coste de un vistazo, un esfuerzo predeterminado que sabe qué admite cada modelo, una lista de modelos con búsqueda agrupada por proveedor con filtros, fijados e interruptores masivos, servidores compatibles con OpenAI con una prueba de conexión real y una actualización que te dice qué hay de nuevo.
- NotificationsLa sección Notificaciones de los ajustes de un producto de IA. Una cuadrícula de canal por evento con toggles por fila, por columna y para todo, horas de silencio con una línea en vivo del próximo silencio, un resumen por correo, envíos de prueba reales para escritorio, correo, push y Slack, gestión de permisos del navegador y un flujo para conectar Slack. Se integra en cualquier sección de Ajustes.