# Form

A form is a group of inputs that allows users to submit data to a server,
with support for providing field validation errors.

## Submitting data

When using React 19, use the `action` prop to handle form submission. This receives a [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) object containing the values for each form field. In React 18 or earlier, use the `onSubmit` event instead. See the [Forms](forms.html) guide details about integrating with frameworks.

## Validation

Use validation props on each form field to prevent submission of invalid values. When `validationBehavior="aria"`, form submission will not be prevented and validation will occur as the value is edited instead of on form submission. See the [Forms](forms.html) guide for more details.

```tsx
import {Form} from 'vanilla-starter/Form';
import {TextField} from 'vanilla-starter/TextField';
import {Button} from 'vanilla-starter/Button';

<Form>
  <TextField
    label="Username"
    isRequired
    validate={value => value === 'admin' ? 'Nice try.' : null}
    name="username"
    defaultValue="admin" />
  <Button type="submit">Submit</Button>
</Form>
```

### Server validation

Use the `validationErrors` prop to provide server validation errors to the fields within a `<Form>`.

```tsx
import {Form} from 'vanilla-starter/Form';
import {TextField} from 'vanilla-starter/TextField';

<Form
  /*- begin highlight -*/
  validationErrors={{
    username: 'This username is not available.'
  }}>
  {/*- end highlight -*/}
  <TextField
    name="username"
    label="Username"
    defaultValue="admin" />
</Form>
```

### Focus management

By default, after a user submits a form with validation errors, the first invalid field will be focused. To prevent this, call `preventDefault()` in the `onInvalid` event. This example moves focus to an [alert](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/alert_role) at the top of the form.

```tsx
import {Form} from 'vanilla-starter/Form';
import {TextField} from 'vanilla-starter/TextField';
import {Button} from 'vanilla-starter/Button';
import {useState} from 'react';

function Example() {
  let [isInvalid, setInvalid] = useState(false);

  return (
    <Form
      /*- begin highlight -*/
      onInvalid={e => {
        e.preventDefault();
        setInvalid(true);
      }}
      /*- end highlight -*/
      onSubmit={e => {
        e.preventDefault();
        setInvalid(false);
      }}
      onReset={() => setInvalid(false)}>
      {isInvalid &&
        <div role="alert" tabIndex={-1} ref={e => e?.focus()}>
          <h3>Unable to submit</h3>
          <p>Please fix the validation errors below, and re-submit the form.</p>
        </div>
      }
      <TextField
        name="firstName"
        isRequired
        label="First Name" />
      <TextField
        name="lastName"
        isRequired
        label="Last Name" />
      <div style={{display: 'flex', gap: 8}}>
        <Button type="submit">Submit</Button>
        <Button type="reset">Reset</Button>
      </div>
    </Form>
  );
}
```

## API

| Name | Type | Default | Description |
|------|------|---------|-------------|
| `action` | `string | ((formData: FormData) => void | Promise<void>) | undefined` | — | Where to send the form-data when the form is submitted. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#action). |
| `aria-describedby` | `string | undefined` | — | Identifies the element (or elements) that describes the object. |
| `aria-details` | `string | undefined` | — | Identifies the element (or elements) that provide a detailed, extended description for the object. |
| `aria-label` | `string | undefined` | — | Defines a string value that labels the current element. |
| `aria-labelledby` | `string | undefined` | — | Identifies the element (or elements) that labels the current element. |
| `autoCapitalize` | `"off" | "on" | "none" | "sentences" | "words" | "characters" | undefined` | — | Controls whether inputted text is automatically capitalized and, if so, in what manner.  See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autocapitalize). |
| `autoComplete` | `"off" | "on" | undefined` | — | Indicates whether input elements can by default have their values automatically completed by the browser. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#autocomplete). |
| `children` | `React.ReactNode` | — | The children of the component. |
| `className` | `string | undefined` | 'react-aria-Form' | The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. |
| `dir` | `string | undefined` | — |  |
| `encType` | `"application/x-www-form-urlencoded" | "multipart/form-data" | "text/plain" | undefined` | — | The enctype attribute specifies how the form-data should be encoded when submitting it to the server. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#enctype). |
| `hidden` | `boolean | undefined` | — |  |
| `id` | `string | undefined` | — | The element's unique identifier. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id). |
| `inert` | `boolean | undefined` | — |  |
| `lang` | `string | undefined` | — |  |
| `method` | `"dialog" | "get" | "post" | undefined` | — | The HTTP method to submit the form with. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#method). |
| `onAnimationEnd` | `React.AnimationEventHandler<HTMLFormElement> | undefined` | — |  |
| `onAnimationEndCapture` | `React.AnimationEventHandler<HTMLFormElement> | undefined` | — |  |
| `onAnimationIteration` | `React.AnimationEventHandler<HTMLFormElement> | undefined` | — |  |
| `onAnimationIterationCapture` | `React.AnimationEventHandler<HTMLFormElement> | undefined` | — |  |
| `onAnimationStart` | `React.AnimationEventHandler<HTMLFormElement> | undefined` | — |  |
| `onAnimationStartCapture` | `React.AnimationEventHandler<HTMLFormElement> | undefined` | — |  |
| `onAuxClick` | `React.MouseEventHandler<HTMLFormElement> | undefined` | — |  |
| `onAuxClickCapture` | `React.MouseEventHandler<HTMLFormElement> | undefined` | — |  |
| `onClick` | `React.MouseEventHandler<HTMLFormElement> | undefined` | — |  |
| `onClickCapture` | `React.MouseEventHandler<HTMLFormElement> | undefined` | — |  |
| `onContextMenu` | `React.MouseEventHandler<HTMLFormElement> | undefined` | — |  |
| `onContextMenuCapture` | `React.MouseEventHandler<HTMLFormElement> | undefined` | — |  |
| `onDoubleClick` | `React.MouseEventHandler<HTMLFormElement> | undefined` | — |  |
| `onDoubleClickCapture` | `React.MouseEventHandler<HTMLFormElement> | undefined` | — |  |
| `onGotPointerCapture` | `React.PointerEventHandler<HTMLFormElement> | undefined` | — |  |
| `onGotPointerCaptureCapture` | `React.PointerEventHandler<HTMLFormElement> | undefined` | — |  |
| `onInvalid` | `((event: React.FormEvent<HTMLFormElement>) => void) | undefined` | — | Triggered for each invalid field when a user submits the form. |
| `onLostPointerCapture` | `React.PointerEventHandler<HTMLFormElement> | undefined` | — |  |
| `onLostPointerCaptureCapture` | `React.PointerEventHandler<HTMLFormElement> | undefined` | — |  |
| `onMouseDown` | `React.MouseEventHandler<HTMLFormElement> | undefined` | — |  |
| `onMouseDownCapture` | `React.MouseEventHandler<HTMLFormElement> | undefined` | — |  |
| `onMouseEnter` | `React.MouseEventHandler<HTMLFormElement> | undefined` | — |  |
| `onMouseLeave` | `React.MouseEventHandler<HTMLFormElement> | undefined` | — |  |
| `onMouseMove` | `React.MouseEventHandler<HTMLFormElement> | undefined` | — |  |
| `onMouseMoveCapture` | `React.MouseEventHandler<HTMLFormElement> | undefined` | — |  |
| `onMouseOut` | `React.MouseEventHandler<HTMLFormElement> | undefined` | — |  |
| `onMouseOutCapture` | `React.MouseEventHandler<HTMLFormElement> | undefined` | — |  |
| `onMouseOver` | `React.MouseEventHandler<HTMLFormElement> | undefined` | — |  |
| `onMouseOverCapture` | `React.MouseEventHandler<HTMLFormElement> | undefined` | — |  |
| `onMouseUp` | `React.MouseEventHandler<HTMLFormElement> | undefined` | — |  |
| `onMouseUpCapture` | `React.MouseEventHandler<HTMLFormElement> | undefined` | — |  |
| `onPointerCancel` | `React.PointerEventHandler<HTMLFormElement> | undefined` | — |  |
| `onPointerCancelCapture` | `React.PointerEventHandler<HTMLFormElement> | undefined` | — |  |
| `onPointerDown` | `React.PointerEventHandler<HTMLFormElement> | undefined` | — |  |
| `onPointerDownCapture` | `React.PointerEventHandler<HTMLFormElement> | undefined` | — |  |
| `onPointerEnter` | `React.PointerEventHandler<HTMLFormElement> | undefined` | — |  |
| `onPointerLeave` | `React.PointerEventHandler<HTMLFormElement> | undefined` | — |  |
| `onPointerMove` | `React.PointerEventHandler<HTMLFormElement> | undefined` | — |  |
| `onPointerMoveCapture` | `React.PointerEventHandler<HTMLFormElement> | undefined` | — |  |
| `onPointerOut` | `React.PointerEventHandler<HTMLFormElement> | undefined` | — |  |
| `onPointerOutCapture` | `React.PointerEventHandler<HTMLFormElement> | undefined` | — |  |
| `onPointerOver` | `React.PointerEventHandler<HTMLFormElement> | undefined` | — |  |
| `onPointerOverCapture` | `React.PointerEventHandler<HTMLFormElement> | undefined` | — |  |
| `onPointerUp` | `React.PointerEventHandler<HTMLFormElement> | undefined` | — |  |
| `onPointerUpCapture` | `React.PointerEventHandler<HTMLFormElement> | undefined` | — |  |
| `onReset` | `((event: React.FormEvent<HTMLFormElement>) => void) | undefined` | — | Triggered when a user resets the form. |
| `onScroll` | `React.UIEventHandler<HTMLFormElement> | undefined` | — |  |
| `onScrollCapture` | `React.UIEventHandler<HTMLFormElement> | undefined` | — |  |
| `onSubmit` | `((event: React.FormEvent<HTMLFormElement>) => void) | undefined` | — | Triggered when a user submits the form. |
| `onTouchCancel` | `React.TouchEventHandler<HTMLFormElement> | undefined` | — |  |
| `onTouchCancelCapture` | `React.TouchEventHandler<HTMLFormElement> | undefined` | — |  |
| `onTouchEnd` | `React.TouchEventHandler<HTMLFormElement> | undefined` | — |  |
| `onTouchEndCapture` | `React.TouchEventHandler<HTMLFormElement> | undefined` | — |  |
| `onTouchMove` | `React.TouchEventHandler<HTMLFormElement> | undefined` | — |  |
| `onTouchMoveCapture` | `React.TouchEventHandler<HTMLFormElement> | undefined` | — |  |
| `onTouchStart` | `React.TouchEventHandler<HTMLFormElement> | undefined` | — |  |
| `onTouchStartCapture` | `React.TouchEventHandler<HTMLFormElement> | undefined` | — |  |
| `onTransitionCancel` | `React.TransitionEventHandler<HTMLFormElement> | undefined` | — |  |
| `onTransitionCancelCapture` | `React.TransitionEventHandler<HTMLFormElement> | undefined` | — |  |
| `onTransitionEnd` | `React.TransitionEventHandler<HTMLFormElement> | undefined` | — |  |
| `onTransitionEndCapture` | `React.TransitionEventHandler<HTMLFormElement> | undefined` | — |  |
| `onTransitionRun` | `React.TransitionEventHandler<HTMLFormElement> | undefined` | — |  |
| `onTransitionRunCapture` | `React.TransitionEventHandler<HTMLFormElement> | undefined` | — |  |
| `onTransitionStart` | `React.TransitionEventHandler<HTMLFormElement> | undefined` | — |  |
| `onTransitionStartCapture` | `React.TransitionEventHandler<HTMLFormElement> | undefined` | — |  |
| `onWheel` | `React.WheelEventHandler<HTMLFormElement> | undefined` | — |  |
| `onWheelCapture` | `React.WheelEventHandler<HTMLFormElement> | undefined` | — |  |
| `role` | `"search" | "presentation" | undefined` | — | An ARIA role override to apply to the form element. |
| `style` | `React.CSSProperties | undefined` | — | The inline [style](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style) for the element. |
| `target` | `"_blank" | "_self" | "_parent" | "_top" | undefined` | — | The target attribute specifies a name or a keyword that indicates where to display the response that is received after submitting the form. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#target). |
| `translate` | `"yes" | "no" | undefined` | — |  |
| `validationBehavior` | `"native" | "aria" | undefined` | 'native' | Whether to use native HTML form validation to prevent form submission when a field value is missing or invalid, or mark fields as required or invalid via ARIA. |
| `validationErrors` | `ValidationErrors | undefined` | — | Validation errors for the form, typically returned by a server. This should be set to an object mapping from input names to errors. |
