React Aria
Build forms with React Aria's built-in validation — no extra libraries required.
This guide shows how to build forms using React Aria's native form capabilities with Kanpeki's Field and Form components.
Demo
Approach
React Aria provides built-in form support without any additional state management library. We combine it with:
Fieldcomponents for layout and accessibilityTextFieldfor automatic ID wiring between label, input, description, and error- HTML constraint validation props (
isRequired,minLength,maxLength,pattern,type) - The
validateprop for custom validation logic validationErrorsonFormfor server-side validation
Anatomy
TextField is Kanpeki's React Aria behavior adapter. It automatically wires Field.Label, Field.Description, and Field.Error via aria-labelledby and aria-describedby. Notice that <Field.Error /> requires no errors prop — React Aria populates it automatically from the field's validation state. See the forms architecture for more.
Setup
No extra dependencies
React Aria Components is already included in Kanpeki. Just import from the registry:
Create your form
Use <Form> and collect values from FormData on submit:
Validation
Constraint props
React Aria integrates with HTML constraint validation. Pass constraints directly on the field component:
Custom validation
Use the validate prop for rules that go beyond built-in constraints. Return an error string to mark the field invalid, or null to indicate it's valid:
Displaying errors
<Field.Error /> requires no props when used inside a <Field.Root /> with a React Aria field as the render prop. Errors are sourced automatically from the field's validation state and cleared as the user corrects input:
Validation behavior
By default (validationBehavior="native"), invalid fields prevent form submission. Use validationBehavior="aria" to report errors to assistive technologies without blocking submission:
Server Validation
Pass server-returned errors to the validationErrors prop on <Form>. React Aria clears each field's error as the user modifies its value:
validationErrors accepts an object mapping each field's name to one or more error messages:
Always validate on the server regardless of client-side constraints. Client validation is for UX; server validation is for security.
Field Types
Input
Textarea
Select
Pass <Select.Root /> as the render prop on <Field.Root />. Use isRequired for constraint validation:
Checkbox
For individual checkboxes, pass <Checkbox.Provider /> as the render prop. Use the name and value props so checkbox values are included in FormData:
Switch
For switches, use useId() to manually wire the label via htmlFor, and provide name and value for form submission:
Submit Button State
Use useActionState (React 19) to track submission state. The third return value isPending is true while the action is running:
For uncontrolled forms using onSubmit, use useTransition to track pending state: