# Form (/components/forms/form)

`Form` groups fields for submission. Beyond a native HTML form, it shares a necessity indicator,
validation behaviour, and server errors with nested Luke UI fields.

Use a layout component such as [`Stack`](/components/layout/stack) to arrange its contents. Prefer
`action` for ordinary submissions and `onSubmit` when you need the submit event or a form library.
Read [Submit](/docs/forms#submit) for the differences.

apps/docs/src/examples/form/basic.tsx

```tsx
import { Button } from '@luke-ui/react/button';
import { Cluster } from '@luke-ui/react/cluster';
import { Form } from '@luke-ui/react/form';
import { Stack } from '@luke-ui/react/stack';
import { Text } from '@luke-ui/react/text';
import { TextInputField } from '@luke-ui/react/text-input-field';
import type { SubmitEvent } from 'react';
import { useState } from 'react';

export default () => {
	const [submitted, setSubmitted] = useState('');

	function handleSubmit(event: SubmitEvent<HTMLFormElement>) {
		event.preventDefault();
		const data = new FormData(event.currentTarget);
		const familyName = data.get('familyName');
		setSubmitted(typeof familyName === 'string' ? familyName : '');
	}

	return (
		<Stack gap="space.16" style={{ maxInlineSize: '20rem' }}>
			<Form necessityIndicator="optional-label" onSubmit={handleSubmit}>
				<Stack gap="space.16">
					<Text elementType="p">All fields are required unless marked optional.</Text>
					<TextInputField isRequired label="Family name" name="familyName" />
					<TextInputField label="Middle name" name="middleName" />
					<Cluster>
						<Button type="submit">Save</Button>
					</Cluster>
				</Stack>
			</Form>
			<Text elementType="p" isVisuallyHidden={!submitted} role="status">
				{submitted ? `Submitted: ${submitted}` : null}
			</Text>
		</Stack>
	);
};
```

## Necessity indicators [#necessity-indicators]

Set `necessityIndicator` on `Form` to choose how nested fields identify required or optional values.
A field's own `necessityIndicator` overrides the Form setting. When neither sets one, required
labels display an asterisk.

The indicator changes the label. It does not make a field required. Set `isRequired` on each
required field.

`Form` does not generate a legend that explains required or optional markers. Read
[Required fields](/docs/forms#required-fields) for when to add one and how the three indicators
differ.

## Validation [#validation]

By default, native validation prevents submission when a field is invalid. Set
`validationBehavior="aria"` when a form library handles validation. An individual field can override
the Form setting.

Pass server errors through `validationErrors`, keyed by each field's `name`.

Read [Validation](/docs/validation) for validation rules, error precedence, and when messages appear
or clear.

## Control sizes [#control-sizes]

Pass `controlSize="small"` for compact fields and actions. A component's explicit `size` takes
precedence. Without an inherited default, controls use `medium`. Sizes select the whole control
recipe, including its typography and icons.

apps/docs/src/examples/form/control-size.tsx

```tsx
import { Button } from '@luke-ui/react/button';
import { CheckboxField } from '@luke-ui/react/checkbox-field';
import { Form } from '@luke-ui/react/form';
import { Stack } from '@luke-ui/react/stack';
import { TextInputField } from '@luke-ui/react/text-input-field';

export default () => (
	<Form controlSize="small">
		<Stack gap="space.16">
			<TextInputField label="Name" />
			<CheckboxField label="Subscribe" />
			<Button size="medium">Save</Button>
		</Stack>
	</Form>
);
```

## Accessibility [#accessibility]

Provide an accessible name for the form landmark when the page has more than one form, or when the
form's purpose is not clear from surrounding content. Pass `aria-label` or `aria-labelledby`.

## API [#api]

### FormProps

Props for the `Form` component.

`FormProps` also accepts compatible DOM and ARIA attributes and event handlers for its rendered element.

| Prop                  | Type                                                                           | Description                                                                                                                                                                                                                   |
| --------------------- | ------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `aria-label?`         | `string`                                                                       | Defines a string value that labels the current element.                                                                                                                                                                       |
| `aria-labelledby?`    | `string`                                                                       | Identifies the element (or elements) that labels the current element.                                                                                                                                                         |
| `aria-describedby?`   | `string`                                                                       | Identifies the element (or elements) that describes the object.                                                                                                                                                               |
| `aria-details?`       | `string`                                                                       | Identifies the element (or elements) that provide a detailed, extended description for the object.                                                                                                                            |
| `id?`                 | `string`                                                                       | The element's unique identifier. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id).                                                                                                           |
| `encType?`            | `'application/x-www-form-urlencoded' \| 'multipart/form-data' \| 'text/plain'` | 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).                                      |
| `method?`             | `'get' \| 'post' \| 'dialog'`                                                  | The HTTP method to submit the form with. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#method).                                                                                                    |
| `target?`             | `'_blank' \| '_self' \| '_parent' \| '_top'`                                   | 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). |
| `onInvalid?`          | `(event: FormEvent<HTMLFormElement>) => void`                                  | Triggered for each invalid field when a user submits the form.                                                                                                                                                                |
| `autoComplete?`       | `'off' \| 'on'`                                                                | 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).                             |
| `autoCapitalize?`     | `'off' \| 'none' \| 'on' \| 'sentences' \| 'words' \| 'characters'`            | 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).                                        |
| `role?`               | `'search' \| 'presentation'`                                                   | An ARIA role override to apply to the form element.                                                                                                                                                                           |
| `children?`           | `ReactNode`                                                                    | The children of the component.                                                                                                                                                                                                |
| `controlSize?`        | `ControlSize`                                                                  | Default recipe size for fields and actions. An explicit component size takes precedence. Default: `'medium'`                                                                                                                  |
| `action?`             | `((formData: FormData) => Promise<void> \| void) \| string \| undefined`       | React form Action or URL for ordinary submissions. Prefer this over `onSubmit` when you do not need the submit event.                                                                                                         |
| `necessityIndicator?` | `NecessityIndicator`                                                           | Controls how nested fields identify required or optional values. A field's own setting takes precedence.                                                                                                                      |
| `onReset?`            | `((event: React.FormEvent<HTMLFormElement>) => void) \| undefined`             | Called when the form is reset.                                                                                                                                                                                                |
| `onSubmit?`           | `SubmitEventHandler<HTMLFormElement>`                                          | Called when the form submits. Use this when you need the submit event, such as calling `preventDefault` or wiring a form library.                                                                                             |
| `validationBehavior?` | `"aria" \| "native" \| undefined`                                              | Determines whether native validation can block submission. Use `'aria'` when a form library handles validation. Default: `'native'`                                                                                           |
| `validationErrors?`   | `ValidationErrors \| undefined`                                                | Server validation errors keyed by field name.                                                                                                                                                                                 |
| `ref?`                | `Ref<HTMLFormElement>`                                                         | Ref forwarded to the form element.                                                                                                                                                                                            |

#### Type definitions

These are the types that this table's signatures and the definitions below name. TypeScript's built-in types, such as `Omit` and `ReadonlyArray`, are not listed.

##### `ControlSize`

```ts
type ControlSize = 'small' | 'medium';
```

##### `NecessityIndicator`

```ts
type NecessityIndicator = 'required-asterisk'
  | 'required-label'
  | 'optional-label';
```

##### `FormEvent`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `ReactNode`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

```ts
type ReactNode = ReactElement
  | string
  | number
  | bigint
  | Iterable<ReactNode>
  | ReactPortal
  | boolean
  | null
  | undefined
  | DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES[keyof DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES]
  | Promise<AwaitedReactNode>;
```

Refers to `ReactElement`, `ReactPortal`, `DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES`, and `AwaitedReactNode`.

##### `ReactElement`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `ReactPortal`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `AwaitedReactNode`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `SubmitEventHandler`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

```ts
type SubmitEventHandler<T = Element> = EventHandler<SubmitEvent<T>>;
```

Refers to `EventHandler` and `SubmitEvent`.

##### `EventHandler`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `SubmitEvent`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `ValidationErrors`

Declared in [`@react-types/shared`](https://www.npmjs.com/package/@react-types/shared) (`src/inputs.d.ts`).

```ts
type ValidationErrors = Record<string, ValidationError>;
```

Refers to `ValidationError`.

##### `ValidationError`

Declared in [`@react-types/shared`](https://www.npmjs.com/package/@react-types/shared) (`src/inputs.d.ts`).

##### `Ref`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

```ts
type Ref<T> = RefCallback<T>
  | RefObject<T | null>
  | null;
```

Refers to `RefCallback` and `RefObject`.

##### `RefCallback`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).

##### `RefObject`

Declared in [`@types/react`](https://www.npmjs.com/package/@types/react) (`index.d.ts`).
