Consuming a feature form
Forms are React Aria Components plus one Zod schema, submitted through the feature’s mutation hook. Your job is to render, wire and brand — never to re-implement validation.
Read the package’s own docs first: which form view it exports, its props, and the Zod schema it exports, which you reuse rather than restate.
Render and wire
Section titled “Render and wire”"use client";import { AddressForm } from "@evolve-storefront/feature-account/address-form";import { useUpdateAddress } from "@evolve-storefront/feature-account";
export function AddressPanel({ defaultValues,}: { defaultValues?: AddressInput;}) { const { mutate, error } = useUpdateAddress();
return ( <AddressForm defaultValues={defaultValues} serverErrors={error?.fieldErrors} onValid={(data) => mutate(data)} /> );}Keep the page thin. Submit goes through the mutation hook, not a Server Action — storefront forms are write-then-stay-and-reconcile, which is what the entity cache is for.
The UX the form already implements
Section titled “The UX the form already implements”Do not fight or reproduce it. Clean on load, with no errors while the user is entering. On the first submit validation becomes visible and submitting is blocked until it is fixed; after that, feedback is live as fields are corrected. The submit button is never disabled — clicking always says why the form is not valid rather than presenting a dead button.
This is deliberately not React Aria’s default, which reveals errors on blur. It works because all
validation is driven through validationErrors rather than native constraints — so do not mix in
isRequired or pattern for display. They fire on blur and fight the timing.
Validate again on the server
Section titled “Validate again on the server”Never trust the client. Run the same exported schema on the backend, return
error.flatten().fieldErrors, and feed them into the form’s serverErrors. Both paths render
through the same validationErrors map, so client and server errors look and clear identically.
Localize error messages server-side — React Aria does not localize custom messages on the client.
Extending
Section titled “Extending”Add a field by composing it into the slot the package exposes and extending the exported schema through its extension seam, so client and server cannot drift.
React Hook Form and TanStack Form stay available as an escalation for genuinely complex client forms — dynamic field arrays, multi-step wizard state. Rare in a storefront, never the default.

