Form is the container the fields sit in, not a field itself. It wraps the native form element so
that grouping, submission and the busy state have one home, without the framework taking
responsibility for your form state: there is no field registry, no validation schema and no
submission state of its own, `isPending` is a prop you set, not a status it discovers. Everything
the platform's form does, `action`, `method`, `encType`, `target`, `noValidate`, the submit
event, passes through untouched.

```tsx demo="forms/form-preview"
```

## Usage

```tsx
import { Form, Input } from "@asheeui/web";

<Form legend="Invoice details" submitLabel="Save invoice" onSubmit={saveInvoice}>
  <Input label="Reference" name="reference" />
  <Input label="Email" name="email" type="email" />
</Form>
```

It owns three things and nothing else: the legend that groups the fields, the submit control that
commits them, and the pending state that control shows while a submission is in flight. Give it a
`legend` and the fields are wrapped in a `fieldset` with that legend; give it a `submitLabel` and
it renders an AsheeUI `Button` in the row at the foot of the form. Omit either and that part is
yours.

The form does not own the values. `onSubmit` is the native event, so a controlled field, a form
library or plain `FormData` all bind to the form exactly as they would to a `<form>`. For the
whole shape, values, validation, focus and submission, see
[Building a form](/guides/building-a-form).

## The pending state

`isPending` marks a submission in flight. The submit control is disabled and busy while it is
true, which stops the second press that a slow request invites, and it keeps its label, so the row
does not move under the pointer.

```tsx demo="forms/form-pending"
```

The fields stay editable: the pending state is about the control that commits, not about freezing
the form, so a reader can still correct a value while the request is in flight.

## Without a legend or a control

Both escape hatches are ordinary omissions. Without `legend` there is no `fieldset`, so name the
form yourself with `aria-label` or `aria-labelledby`; without `submitLabel` there is no button, so
place your own, a `type="submit"` control inside the form still fires the native submit event.

```tsx demo="forms/form-own-control"
```

The element itself can be replaced the way the framework's `Link` replaces an anchor:
`component` names a form primitive and `componentProps` carries the props it needs, so a
framework's own form component sits where the native one did.

## Props

```props Form
```

The defaults describe a control rather than a layout. `isPending` is off; without `legend` and
`submitLabel` the component renders no grouping and no control. The submit control's variant and
colour come from the application's `defaultVariant` and `defaultColor`, `faded` and `primary` out
of the box, while its size is `md` and its radius is registered as `md`. All four can be restated
once under `components.form` as `submitVariant`, `submitColor`, `submitSize` and `submitRadius`,
or overridden per form with the props of the same names.

## Accessibility

- The element is a real `<form>`, so native submission, validation and autofill work, and a
  submission triggered by <kbd>Enter</kbd> in a single-line field is the browser's, not a
  simulation of it.
- With `legend`, the fields are a `fieldset` named by a `legend`, and the group is announced
  before its controls. Without it the component adds no name of its own: give the form
  `aria-label` or point `aria-labelledby` at the heading that describes it.
- The submit control is a `<button type="submit">`, so it is reached and pressed by keyboard like
  any other button and it submits without a click handler. While `isPending` it is disabled and
  busy through `aria-disabled` and `aria-busy`, and its label does not change, the announcement
  says what is happening, not what replaced the label.
- The form never moves focus, on mount or after a rejected submission. Where focus goes after a
  validation failure is your decision, which is why the component does not make one.

## Related

```related stepper, input, button
```
