Wave 3
Form
A form validated by a Zod schema on submit, with errors shown next to each field.
- A single search field: use Input.
Install
Terminal
pnpm dlx shadcn@latest add @acme/formOr import from the package: import { Form } from '@acme/react'
Examples
Schema
form-schema.tsx
'use client'
import { useState } from 'react'
import { z } from 'zod'
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
import { Button } from '@/components/ui/button'
import { Field, FieldDescription, FieldError, FieldLabel } from '@/components/ui/field'
import { Form } from '@/components/ui/form'
import { Input } from '@/components/ui/input'
const schema = z.object({
company: z.string().min(2, 'Enter your company name.'),
email: z.email('Enter an email like name@company.com.'),
seats: z.coerce
.number('Enter a number.')
.int()
.min(1, 'At least 1 seat.')
.max(500, 'Up to 500 seats; contact sales for more.'),
})
export default function FormSchema() {
const [done, setDone] = useState<z.infer<typeof schema> | null>(null)
return (
<div className="flex w-full max-w-sm flex-col gap-4">
<Form schema={schema} onSubmit={setDone}>
<Field name="company">
<FieldLabel>Company</FieldLabel>
<Input autoComplete="organization" />
<FieldError />
</Field>
<Field name="email">
<FieldLabel>Billing email</FieldLabel>
<Input type="email" autoComplete="email" />
<FieldError />
</Field>
<Field name="seats">
<FieldLabel>Seats</FieldLabel>
<Input inputMode="numeric" defaultValue="5" />
<FieldDescription>You can add more later.</FieldDescription>
<FieldError />
</Field>
<div>
<Button type="submit">Start trial</Button>
</div>
</Form>
{done ? (
<Alert variant="success">
<AlertTitle>Trial started</AlertTitle>
<AlertDescription>
{done.company}, {done.seats} seats. We emailed {done.email}.
</AlertDescription>
</Alert>
) : null}
</div>
)
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| schema (required) | ZodType | — | Validation schema; keys match each Field name. |
| onSubmit (required) | (values) => void | Promise<void> | — | Called with parsed, typed values when the schema passes. |
| serverErrors | Record<string, string | string[]> | — | Errors from the server, keyed by field name. |
Accessibility
| Key | Action |
|---|---|
| Enter | Submits from a text field |
- Role
- form
- You provide
- A Field with name, FieldLabel and FieldError for each input.
- A submit Button.
- Built in
- On a failed submit, focus moves to the first invalid field (WCAG 3.3.1).
- Errors are linked to their inputs with aria-describedby and aria-invalid.
- Native browser validation bubbles are off (noValidate); the schema is the single source of rules.
- WCAG 2.2 criteria
- 3.3.1, 3.3.2, 3.3.3, 4.1.2
Don’t
- Validate on every keystroke.
- Clear what people typed when validation fails.
Tokens
- color.destructive