Skip to content

Forms

Build forms with explicit field structure

Form components are designed around labels, descriptions, errors, loading states, and server feedback so validation remains understandable.

Form components

Field

Layout primitive for label, description, control, and error text.

Form

React Hook Form bridge with field context and message helpers.

Input OTP

One-time-code fields with grouped slots and keyboard-friendly entry.

FileDropzone

Upload state, accepted files, rejected files, and screen-reader feedback.

React Hook Form and Zod

Use the native form event, keep validation schema close to the form, and render messages through FieldError.

tsx
import { zodResolver } from "@hookform/resolvers/zod";
import { Button, Field, FieldDescription, FieldError, FieldLabel, Input } from "@cooud-ui/ui";
import { useForm } from "react-hook-form";
import { z } from "zod";
const schema = z.object({
email: z.string().email()
});
export function InviteForm() {
const form = useForm({
resolver: zodResolver(schema),
defaultValues: { email: "" }
});
return (
<form onSubmit={form.handleSubmit(console.log)} className="grid gap-4">
<Field>
<FieldLabel htmlFor="email">Email</FieldLabel>
<Input id="email" type="email" {...form.register("email")} />
<FieldDescription>Use the teammate work email.</FieldDescription>
<FieldError>{form.formState.errors.email?.message}</FieldError>
</Field>
<Button type="submit">Send invite</Button>
</form>
);
}

Checklist

  • Every input has a visible label or an explicit accessible name.
  • Descriptions and errors are adjacent to the field they explain.
  • Server-side errors map back to the same field component.
  • Submit buttons expose loading and disabled states without losing text.
  • Validation does not depend on color alone.

For framework routes, loader/action errors should return data that maps back to FieldError or the same field-level error region.