Instalación
npx logic2b@next add formAnatomía
import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import { z } from "zod"
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form"
const formSchema = z.object({
username: z.string().min(2),
})
function ProfileForm() {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: { username: "" },
})
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(console.log)}>
<FormField
control={form.control}
name="username"
render={({ field }) => (
<FormItem>
<FormLabel>Nombre de usuario</FormLabel>
<FormControl>
<input {...field} />
</FormControl>
<FormDescription>Tu nombre público.</FormDescription>
<FormMessage />
</FormItem>
)}
/>
</form>
</Form>
)
}
FormField envuelve el Controller de react-hook-form y proporciona el contexto del campo a FormLabel, FormControl, FormDescription y FormMessage. Estas piezas leen el error y el identificador desde ese contexto, por lo que etiquetas y mensajes permanecen conectados al control correcto.
Notas de uso
Form es un alias de FormProvider. Pásale el valor devuelto por useForm; el resto de piezas consumen su contexto.
Ejemplos
Inicio de sesión
Valida un correo electrónico y una contraseña con zod.
Área de texto
Accesibilidad
FormControlobtieneid,aria-describedbyyaria-invaliddel contexto del campo. La etiqueta, la descripción y el error quedan conectados sin coordinarhtmlForeidmanualmente.- Cuando falla la validación,
FormMessagemuestra el error con el identificador referenciado poraria-describedby, mientrasFormLabeladopta el estado destructivo. El error se comunica visualmente y a tecnologías de asistencia. - Cada control recibe un identificador generado único, incluso cuando un campo se reutiliza dentro de una lista.
Playground interactivo
Edita las propiedades del componente y revisa el JSX exacto antes de copiarlo. La vista previa se carga solo cuando esta sección entra en pantalla.
const form = useForm({
defaultValues: { username: "" },
})
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(console.log)}>
<FormField
control={form.control}
name="username"
rules={{ required: "Username is required." }}
render={({ field }) => (
<FormItem>
<FormLabel>Username</FormLabel>
<FormControl>
<Input
{...field}
placeholder={"logic2b"}
/>
</FormControl>
<FormDescription>{"This is your public display name."}</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Save profile</Button>
</form>
</Form>
)Referencia de API
Generada a partir de las exportaciones públicas de TypeScript en src/ui/form.tsx. Las descripciones técnicas conservan el texto canónico del código fuente.
useFormField
Hook(): { invalid: boolean; isDirty: boolean; isTouched: boolean; isValidating: boolean; error?: FieldError; id: string; name: string; formItemId: string; formDescriptionId: string; formMessageId: string; }Form
ComponenteAlias directo de FormProvider.
FormItem
ComponenteProps: React.ComponentProps<"div">FormLabel
ComponenteProps: React.ComponentProps<typeof Label>FormControl
ComponenteProps: React.ComponentProps<typeof Slot.Root>FormDescription
ComponenteProps: React.ComponentProps<"p">FormMessage
ComponenteProps: React.ComponentProps<"p">FormField
ComponenteProps: ControllerProps<TFieldValues, TName>Contrato de accesibilidad
Comportamiento legible por máquinas y responsabilidades de quien integra form. Los detalles normativos conservan el texto canónico del registro.
- Soporte
- Comportamiento implementado
- Patrón
- form validation
- React Hook Form + Radix Label
Semántica incorporada
- FormControl derives id, aria-invalid and aria-describedby from field state.
- Descriptions and error messages receive stable ids.
Responsabilidades de integración
- Render FormLabel and useful error text; move focus or provide a summary after failed submission.