Registration form example

This is a simple registration form example. It showcases our highly accessible client-side validation with error summary for easy screen-reader navigation.

Create an account

Please enter your full name without any middle names
Please enter a valid email address. Example: test@test.com
Please enter your phone number with the country code. Example: +43
Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, and one number.
Favorite Animal (Required)
Country (Required)
Preferred Contact Method (Required)We will contact you via the method you select
Read our full Terms and Conditions

registration-form.tsx

'use client';
 
import {
  RiEarthLine,
  RiHeart2Line,
  RiLockPasswordLine,
  RiPhoneLine,
} from '@remixicon/react';
import Link from 'next/link';
import { Button } from '@/components/button/button';
import { Checkbox } from '@/components/forms/checkbox';
import {
  Combobox,
  ComboboxItem,
  ComboboxListBox,
  ComboboxSearchField,
} from '@/components/forms/combobox';
import { Form, FormRoot } from '@/components/forms/form';
import { useForm } from '@/components/forms/hooks/use-form';
import { Radio, RadioGroup } from '@/components/forms/radio';
import { Select, SelectItem } from '@/components/forms/select';
import { TextField } from '@/components/forms/text-field';
import {
  FieldErrorSummary,
  FormErrors,
  FormServerError,
  validators,
} from '@/components/forms/validation';
import { registerAction } from './action';
import { RegistrationFormValues } from './types';
 
export const RegistrationForm = () => {
  const form = useForm<RegistrationFormValues>({
    onSubmit: async ({ values, reset }) => {
      await registerAction(values);
      reset();
    },
  });
 
  return (
    <FormRoot context={form}>
      <h2 id="registration-form-heading" className="mb-4 text-3xl font-bold">
        Create an account
      </h2>
 
      <FormStatus>
        <FormServerError
          errorMessage={form.serverError}
          title="Could not register"
        />
        <FieldErrorSummary
          title="Something went wrong!"
          subtitle="The form could not be submitted because some of the fields are invalid. Please correct your input in the following 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',
          }}
        />
      </FormStatus>
 
      <Form
        className="flex flex-col gap-4 rounded-lg border-2 border-gray-200 p-6 shadow-xl"
        aria-labelledby="registration-form-heading"
      >
        <TextField
          id="name"
          name="name"
          label="Name"
          type="text"
          description="Please enter your full name without any middle names"
          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"
          autoComplete="email"
          validate={(value) => {
            if (!validators.email(value)) {
              return 'Invalid email address';
            }
          }}
          isRequired
        />
 
        <TextField
          id="phone"
          name="phone"
          label="Phone Number"
          type="tel"
          icon={<RiPhoneLine size={20} />}
          description="Please enter your phone number with the country code. Example: +43"
          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."
          autoComplete="new-password"
          icon={<RiLockPasswordLine size={18} />}
          isRequired
          validate={(value) => {
            if (value.length < 8) {
              return 'Password must be at least 8 characters long';
            }
            if (!/[A-Z]/.test(value)) {
              return 'Password must contain at least one uppercase letter';
            }
            if (!/[a-z]/.test(value)) {
              return 'Password must contain at least one lowercase letter';
            }
            if (!/[0-9]/.test(value)) {
              return 'Password must contain at least one number';
            }
          }}
        />
 
        <Select
          id="favoriteAnimal"
          name="favoriteAnimal"
          label="Favorite Animal"
          icon={<RiHeart2Line size={18} />}
          isRequired
          validate={(value) => {
            if (!value) {
              return 'Please select an animal';
            }
            if (value === 'snake') {
              return 'Please select a non-snake as your favorite animal';
            }
          }}
        >
          <SelectItem id="cat">Cat</SelectItem>
          <SelectItem id="dog">Dog</SelectItem>
          <SelectItem id="kangaroo">Kangaroo</SelectItem>
          <SelectItem id="panda">Panda</SelectItem>
          <SelectItem id="snake">Snake</SelectItem>
          <SelectItem id="lion">Lion</SelectItem>
          <SelectItem id="tiger">Tiger</SelectItem>
          <SelectItem id="elephant">Elephant</SelectItem>
          <SelectItem id="giraffe">Giraffe</SelectItem>
          <SelectItem id="zebra">Zebra</SelectItem>
          <SelectItem id="hippo">Hippo</SelectItem>
          <SelectItem id="rhino">Rhino</SelectItem>
          <SelectItem id="leopard">Leopard</SelectItem>
          <SelectItem id="cheetah">Cheetah</SelectItem>
          <SelectItem id="monkey">Monkey</SelectItem>
          <SelectItem id="fox">Fox</SelectItem>
          <SelectItem id="wolf">Wolf</SelectItem>
        </Select>
 
        <Combobox
          id="country"
          name="country"
          label="Country"
          isRequired
          icon={<RiEarthLine size={18} />}
          validate={(value) => {
            if (!value) {
              return 'Please select a country';
            }
          }}
        >
          <ComboboxSearchField placeholder="Search country..." />
          <ComboboxListBox>
            <ComboboxItem id="austria">Austria</ComboboxItem>
            <ComboboxItem id="ireland">Ireland</ComboboxItem>
            <ComboboxItem id="poland">Poland</ComboboxItem>
            <ComboboxItem id="uk">United Kingdom</ComboboxItem>
            <ComboboxItem id="hungary">Hungary</ComboboxItem>
            <ComboboxItem id="spain">Spain</ComboboxItem>
            <ComboboxItem id="portugal">Portugal</ComboboxItem>
            <ComboboxItem id="kangaroo">Australia</ComboboxItem>
            <ComboboxItem id="in">India</ComboboxItem>
            <ComboboxItem id="br">Brazil</ComboboxItem>
            <ComboboxItem id="mx">Mexico</ComboboxItem>
            <ComboboxItem id="it">Italy</ComboboxItem>
            <ComboboxItem id="es">Spain</ComboboxItem>
            <ComboboxItem id="se">Sweden</ComboboxItem>
            <ComboboxItem id="no">Norway</ComboboxItem>
            <ComboboxItem id="fi">Finland</ComboboxItem>
          </ComboboxListBox>
        </Combobox>
 
        <RadioGroup
          id="contactMethod"
          name="contactMethod"
          label="Preferred Contact Method"
          description="We will contact you via the method you select"
          isRequired
          validate={(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"
          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"
            disabled={form.isPending}
            loading={form.isPending}
          >
            Create your account
          </Button>
        </div>
      </Form>
    </FormRoot>
  );
};