Form
The container that groups fields, submits them, and owns the pending state.
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.
Usage
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.
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.
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.
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
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 Enter in a single-line field is the browser's, not a simulation of it. - With
legend, the fields are afieldsetnamed by alegend, and the group is announced before its controls. Without it the component adds no name of its own: give the formaria-labelor pointaria-labelledbyat 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. WhileisPendingit is disabled and busy througharia-disabledandaria-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.