Skip to content

Form

Form root. A native <form> that seeds RAC's FormContext, so it takes the standard form events with full typing while RAC fields pick up their validationErrors by name. Client errors go in validationErrors (e.g. zod.flatten().fieldErrors), server errors in serverErrors, mapped by code. method defaults to "post", so a submit that lands before hydration sends the fields in the body, never in the URL. See the evolve-feature-form skill for the submit-then-live pattern.

import { Form } from "@evolve-storefront/ui/form";

Preview

DefaultOpen in Storybook ↗

Usage

<Form validationErrors={errors} onSubmit={submit}>
<TextField name="email" required>
<Label>{t("email")}</Label>
<Input type="email" />
<FieldError />
</TextField>
<Button type="submit">{t("save")}</Button>
</Form>;

Props

PropTypeDescription
validationErrors?FormValidationErrors

Field-error map driving display. RAC fields read their own entry by name, and it shows until the map changes — the owner revalidates as the user edits.

serverErrors?FormValidationErrors

Server-provided field errors (the mapped result of a failed mutation's typed errors — see @evolve-storefront/errors). Merged over validationErrors, and the first errored field is focused, so a failed submit surfaces the same way as client validation. A field's entry clears once the user edits that field, until the next map arrives.

validationBehavior?"aria" | "native"

Default "aria": mark fields via ARIA rather than blocking native submit. The form is then noValidate, so an input's own constraint (type="email") never stops the submit with a browser tooltip that the field's error does not match.

Any other props go to the root element, like on a plain HTML element.

Examples

With Validation ErrorsClient validation: the map from zod.flatten().fieldErrors, keyed by field name.
const result = schema.safeParse(values);
<Form validationErrors={result.success ? undefined : result.error.flatten().fieldErrors}>
…
</Form>;
Open in Storybook ↗
With Server ErrorsServer errors win over client ones, and the first errored field takes focus.
// Mapped from the failed mutation's typed errors, never its raw message.
<Form validationErrors={clientErrors} serverErrors={serverErrors}>
…
</Form>;
Open in Storybook ↗