Submit information with accessible interactive controls in React. Take advantage of the browser's built-in validation with screen reader support. This component is based on the WAI-ARIA Form Role.

Add new participant

import {
} from "ariakit/form";
import "./style.css";

export default function Example() {
  const form = useFormState({ defaultValues: { name: "", email: "" } });

  form.useSubmit(async () => {

  return (
      <h2 id="add-new-participant" className="heading">
        Add new participant
      <div className="field">
        <FormLabel name={}>Name</FormLabel>
        <FormInput name={} required placeholder="John Doe" />
        <FormError name={} className="error" />
      <div className="field">
        <FormLabel name={}>Email</FormLabel>
        <FormError name={} className="error" />
      <div className="buttons">
        <FormReset className="button secondary reset">Reset</FormReset>
        <FormSubmit className="button">Add</FormSubmit>


npm install ariakit

Learn more in Getting started.



    <FormGroupLabel />
    <FormLabel />
    <FormField|FormInput|FormCheckbox />
    <FormDescription />
    <FormError />
    <FormPush />
    <FormRemove />
    <FormRadio />
  <FormReset />
  <FormSubmit />

Submitting the form

The useFormState function returns a useSubmit hook that can be used to register a submit handler on the form state. All registered handlers run when the user submits the form or the program calls the submit function.

Submit handlers may return a promise and interact with the form state. This means we can access the form values and call methods such as setErrors to display errors when the form is submitted:

const form = useFormState();

form.useSubmit(async () => {
  const response = await fetch("", {
    method: "POST",
    body: JSON.stringify(form.values),
    headers: {
      "Content-type": "application/json; charset=UTF-8",
  if (!response.ok) {
    form.setErrors(await response.json());

Validating the form

Built-in validation

Ariakit supports the browser's built-in validation. We can use props like required, minLength, maxLength, min, max, type, and pattern to add simple validation to our form fields.

This method has a great advantage: the error messages are automatically localized to the user's language by the browser. However, the default UI doesn't necessarily follow accessibility standards. Also, the style of the error messages is not customizable, and we can't control when they are displayed.

Thankfully, JavaScript allows us to hook into this validation process using the Constraint Validation API, which FormField uses internally. This way, we can display the error messages in a way that is accessible and customizable.

Custom validation

Similar to Submitting the form, the useFormState function also returns a useValidate hook that can be used to register a validation handler on the form state.

We can pass this hook to other components as a prop to create field-level validations:

function MyForm() {
  const form = useFormState({ defaultValue: { name: "" } });
  return (
    <Form state={form}>
      <NameInput state={form} name={} />

function NameInput({ state, name, ...props }) {
  state.useValidate(() => {
    const value = state.getValue(name);
    if (value.length < 3) {
      state.setError(name, "Name must be at least 3 characters long");
  return <FormInput name={name} {...props} />;


Styling the invalid state

The FormField component — which is used by FormInput, FormCheckbox, FormRadio, and other form components — sets the aria-invalid attribute to true when the field is invalid. You can use this attribute to style the invalid state:

.field[aria-invalid="true"] {
  /* ... */

Learn more in Styling.