Component

A form that validates its Fields before submitting, focuses the first invalid one, and shows server errors on the right field.

View component changelog
preview

React
"use client" import { useState } from "react" import Form from "@radui/ui/Form" import Field from "@radui/ui/Field" import TextField from "@radui/ui/TextField" import Button from "@radui/ui/Button" // Submitting checks every field; an email starting with "taken" comes back as a server error. export default function FormExample() { const [errors, setErrors] = useState<Record<string, string>>({}) const [status, setStatus] = useState("") return ( <Form className="flex w-full max-w-[360px] flex-col gap-4" errors={errors} onFormSubmit={(values) => { if (String(values.email).startsWith("taken")) { setErrors({ email: "That email already has an account." }) setStatus("") return } setStatus(`Welcome, ${values.name}!`) }} > <Field.Root name="name" required> <Field.Label>Name</Field.Label> <Field.Control asChild> <TextField /> </Field.Control> <Field.Error match="valueMissing">Enter your name.</Field.Error> </Field.Root> <Field.Root name="email" required> <Field.Label>Email</Field.Label> <Field.Control asChild> <TextField type="email" placeholder="ada@example.com" /> </Field.Control> <Field.Error /> </Field.Root> <Button type="submit">Sign up</Button> <p role="status">{status}</p> </Form> ) }
  • Validates every Field on submit and focuses the first invalid one
  • Uses the browser's constraint validation (required, type, pattern, min, max) plus each Field's validate function
  • Maps server errors to fields by name and clears each one as the user edits it
  • onFormSubmit receives the values as an object, with repeated names collected into arrays

Import all parts of the component and piece them together

React
import Form from "@radui/ui/Form" import Field from "@radui/ui/Field" export default () => { return ( <Form> <Field.Root> <Field.Label /> <Field.Control /> <Field.Error /> </Field.Root> </Form> ) }

Renders a <form> with browser validation bubbles off. On submit it validates every Field inside; with invalid fields it shows their errors and focuses the first, otherwise it calls onSubmit and onFormSubmit.

PropTypeDefault
errors
Record<string, string | string[]>
--
onFormSubmit
(values, event) => void
--
onClearErrors
(errors) => void
--
validationMode
'onSubmit' | 'onBlur' | 'onChange'
'onSubmit'
noValidate
boolean
true
asChild
boolean
false
customRootClass
string
""
actionsRef
Ref<{ validate(name?): boolean }>
--
ShortcutDescription
Enter

Submits the form from a text control, which validates every field first.

ReferenceWhat Rad UI follows

Each invalid control gets aria-invalid and its error in aria-describedby; the error is announced with role="alert".