Forms
TaylorUI uses react-aria-components to build accessible forms and provides a set of pre-built form elements.
- Supports client-side and server side validation
- All form components meet our A11y standards
'use client';
import Link from 'next/link';
import { Button } from '@/ui/components/button/button';
import { Checkbox } from '@/ui/components/forms/checkbox';
import { Form } from '@/ui/components/forms/form';
import { useFormAction } from '@/ui/components/forms/hooks/use-form-action';
import { Radio, RadioGroup } from '@/ui/components/forms/radio';
import { Select, SelectItem } from '@/ui/components/forms/select';
import { TextField } from '@/ui/components/forms/text-field';
import {
FieldErrorSummary,
FormErrors,
ServerError,
validators,
} from '@/ui/components/forms/validation';
import { registerAction } from './actions';
export const RegistrationFormExample = () => {
const form = useFormAction<{
name: string;
email: string;
phone: string;
password: string;
favoriteAnimal: string;
contactMethod: string;
country: string;
'terms-and-conditions': boolean;
}>(registerAction);
return (
<Form
action={form.action}
className="flex max-w-lg flex-col gap-4 rounded-lg border-2 border-gray-200 p-4 shadow-xl"
validationErrors={form.fieldErrors}
>
<h2 className="mb-4 text-3xl font-bold">Create an account</h2>
<FormErrors>
{/* Error message for things that go wrong on the server */}
{form.serverError && !form.isPending && (
<ServerError title="Could not register">
{form.serverError}
</ServerError>
)}
{/* Error message for mistakes the user makes in the form */}
<FieldErrorSummary
title="There are errors in your submission"
subtitle="Please correct your input in these fields:"
fieldLabels={{
name: 'Name',
email: 'Email Address',
phone: 'Phone Number',
password: 'Password',
favoriteAnimal: 'Favorite Animal',
contactMethod: 'Preferred Contact Method',
country: 'Country',
'terms-and-conditions': 'Terms and Conditions',
}}
/>
</FormErrors>
<TextField
id="name"
name="name"
label="Name"
type="text"
description="Please enter your full name without any middle names"
defaultValue={form.defaultValues.name}
autoComplete="name"
isRequired
validate={(value) => {
if (!value) {
return 'Please enter your name';
}
}}
/>
<TextField
id="email"
name="email"
label="Email Address"
type="email"
description="Please enter a valid email address. Example: test@test.com"
defaultValue={form.defaultValues.email}
autoComplete="email"
validate={(value) => {
if (!validators.email(value)) {
return 'Invalid email address';
}
}}
isRequired
/>
<TextField
id="phone"
name="phone"
label="Phone Number"
type="tel"
description="Please enter your phone number with the country code. Example: +43"
defaultValue={form.defaultValues.phone}
autoComplete="tel"
/>
<TextField
id="password"
name="password"
label="Password"
type="password"
description="Password must be at least 8 characters long and contain at least one
uppercase letter, one lowercase letter, and one number."
defaultValue={form.defaultValues.password}
autoComplete="new-password"
isRequired
validate={validatePassword}
/>
<Select
id="favoriteAnimal"
name="favoriteAnimal"
label="Favorite Animal"
isRequired
defaultValue={form.defaultValues.favoriteAnimal}
validate={(value) => {
if (!value) {
return 'Please select an animal';
}
}}
>
{animals.map((animal) => (
<SelectItem key={animal.id} id={animal.id}>
{animal.name}
</SelectItem>
))}
</Select>
<Combobox
id="country"
name="country"
label="Country"
isRequired
validate={(value) => {
if (!value) {
return 'Please select a country';
}
}}
>
<ComboboxSearchField placeholder="Search country..." />
<ComboboxListBox>
{countries.map((country) => (
<ComboboxItem key={country.id} id={country.id}>
{country.name}
</SelectItem>
))}
</ComboboxListBox>
</Combobox>
<RadioGroup
id="contactMethod"
name="contactMethod"
label="Preferred Contact Method"
isRequired
defaultValue={form.defaultValues.contactMethod}
validate={(value) => {
console.log('RADIO VALIDATION', value);
if (!value) {
return 'Please select a contact method';
}
if (value === 'pigeon') {
return 'Please select a modern contact method';
}
}}
orientation="vertical"
>
<Radio value="email">Email</Radio>
<Radio value="phone">Phone</Radio>
<Radio value="pigeon">Carrier Pigeon</Radio>
</RadioGroup>
<Checkbox
id="terms-and-conditions"
name="terms-and-conditions"
value="terms-and-conditions"
label="I agree to the terms and conditions"
defaultSelected={!!form.defaultValues['terms-and-conditions']}
description={
<>
Read our full{' '}
<Link
href="/terms-and-conditions"
className="text-primary-500 hover:underline"
>
Terms and Conditions
</Link>
</>
}
isRequired
validate={(value) => {
if (!value) {
return 'Please agree to the terms and conditions';
}
}}
className="pt-2"
/>
<div>
<Button type="submit">Submit</Button>
</div>
</Form>
);
};