Ariakit
/

Form

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 * as Ariakit from "@ariakit/react";
import "./style.css";
export default function Example() {
const form = Ariakit.useFormStore({ defaultValues: { name: "", email: "" } });
form.useSubmit(async (state) => {
alert(JSON.stringify(state.values));
});
return (
store={form}
aria-labelledby="add-new-participant"
className="wrapper"
>
<h2 id="add-new-participant" className="heading">
Add new participant
</h2>
<div className="field">
<Ariakit.FormLabel name={form.names.name}>Name</Ariakit.FormLabel>
name={form.names.name}
placeholder="John Doe"
className="input"
required
/>
<Ariakit.FormError name={form.names.name} className="error" />
</div>
<div className="field">
<Ariakit.FormLabel name={form.names.email}>Email</Ariakit.FormLabel>
type="text"
name={form.names.email}
placeholder="johndoe@example.com"
className="input"
required
/>
<Ariakit.FormError name={form.names.email} className="error" />
</div>
<div className="buttons">
<Ariakit.FormReset className="button secondary reset">
Reset
<Ariakit.FormSubmit className="button">Add</Ariakit.FormSubmit>
</div>
);
}

API

Submitting the form

The useFormStore function returns a useSubmit hook that can be used to register a submit handler on the form store. 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 store. This means we can access the form values and call methods such as setErrors to display errors when the form is submitted:

const form = useFormStore();
form.useSubmit(async (state) => {
const response = await fetch("https://jsonplaceholder.typicode.com/posts", {
method: "POST",
body: JSON.stringify(state.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 FormControl 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 useFormStore function also returns a useValidate hook that can be used to register a validation handler on the form store.

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

function MyForm() {
const form = useFormStore({ defaultValue: { name: "" } });
return (
<Form store={form}>
<NameInput store={form} name={form.names.name} />
</Form>
);
}
function NameInput({ store, name, ...props }) {
store.useValidate(() => {
const value = store.getValue(name);
if (value.length < 3) {
store.setError(name, "Name must be at least 3 characters long");
}
});
return <FormInput name={name} {...props} />;
}

Styling

Styling the invalid state

The FormControl 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 on the Styling guide.

Stay tuned

Join 1,000+ subscribers and receive monthly tips & updates on new Ariakit content.

No spam. Unsubscribe anytime. Read latest issue