How to build an accessible Form in React

Renders a native <form> with noValidate so validation messages come from the component (surfaced per field via Input error/role="alert") rather than inconsistent browser bubbles, while Enter-to-submit and the form role are preserved by the platform element.

When to use a Form

When not to use it

Keyboard interactions

Role form, verified at WCAG 2.2-AA.

Common mistakes

Avoid: <form onSubmit={...}> with hand-rolled useState per field

Prefer: const form = useForm({ initialValues, validate }); <Form form={form} onValid={...}>

The store centralizes values, errors, touched, and submitting as signals; rolling your own reintroduces the re-render and validation-timing bugs the store solves

Example

function Demo() {
  const form = useForm({
    initialValues: { email: '' },
    validate: (v) => v.email.includes('@') ? {} : { email: 'Invalid email' },
  })
  const email = form.field('email')
  return (
    <Form form={form} onValid={console.log}>
      <Input
        label="Email"
        value={email.value}
        onChange={(e) => email.onChange(e.currentTarget.value)}
        onBlur={email.onBlur}
        error={email.error}
      />
      <Button type="submit">Save</Button>
    </Form>
  )
}

See the full Form reference →