Skip to content

Form

Form is a native <form> that knows about the Fields inside it. It collects their values by name on submit, refuses to submit while any of them is invalid and moves focus to the first one that failed, and routes an errors object from your server back to the right message.

form/basic.tsx
Plan

Four different controls, no onChange handlers, no form state library, no useState per field. Every one of them reaches values under the name on its Field.Root: Input as a string, Select as the chosen value, Checkbox and Switch as booleans.

Import

import { Form } from "@forte-ui/react";

Examples

Server errors

Constraint validation catches what the browser can see. Everything else — uniqueness, permissions, anything that needs a round trip — comes back from the server, and errors is how it gets to the right field. Keys match the name on a Field.Root; values are a message or an array of them.

form/server-errors.tsx

Base UI mirrors errors into its own state and drops a field's entry as soon as that field changes. A server error describes a value the server has seen, so it stops being true the moment the value moves — there is nothing to clear by hand.

Validation timing

validationMode on the form sets the default for every field in it; validationMode on an individual Field.Root overrides it.

ModeValidatesReach for it when
onSubmit (default)On submit, then on every change afterwardsAlmost always. It does not interrupt someone mid-answer, and once they have seen an error it corrects live.
onBlurWhen a control loses focusLong forms where a per-field verdict as you move down the page is genuinely useful.
onChangeOn every changeA value with an expensive or remote check — pair it with validationDebounceTime on the field.

Accessibility

Base UI calls preventDefault() on the native submit event when onFormSubmit is used, so onFormSubmit replaces onSubmit rather than sitting beside it. The element is still a real <form>, so action, method and a native non-JavaScript submit all work when you leave onFormSubmit off.

Each field's message is wired into its own control's aria-describedby — there is no error summary at the top of the form. Add one yourself for long forms; SC 3.3.1 is satisfied either way, but a summary saves a lot of scrolling.

Theming

Form carries almost no styling — a <form> has no UA presentation worth undoing. It lays out as a column because a form is nearly always a stack of fields, and without it every consumer writes the same three declarations. Set display through className for anything else.

Theming tokens for Form
PropertyControlsDefault
--forte-form-gapSpace between the form's childrenvar(--forte-space-5)

min-inline-size: 0 is set for the same reason it is on Field and Fieldset: a text input inside refuses to shrink below its ~20-character intrinsic width, so without it the form overflows a narrow column rather than letting its fields wrap.

API reference

Form

Props for Form
PropTypeDefaultDescription
actionsRefRefObject<FormActions | null>A ref to imperative actions. `validate()` runs every field; pass a field name to run just one.
classNamestringAdditional class name(s). Applied after the internal styles so consumer utilities (e.g. Tailwind) win without needing `!important`.
errorsErrorsErrors that came from somewhere other than the browser — a server response, a form action, a schema parse. Keys are the `name` of a `Field.Root`; values are a message or an array of messages, which the matching `Field.Error` then renders.
onFormSubmit((formValues: FormValues, eventDetails: { reason: "none"; event: Event; }) => void)Called on submit once every field passes validation, with the form's values collected by `name`. Base UI calls `preventDefault()` on the native event for you, so this replaces `onSubmit` rather than sitting beside it.
refRef<HTMLFormElement>Ref to the underlying `<form>` element. Declared explicitly rather than through `forwardRef` because the component is generic — a `forwardRef` wrapper would erase `FormValues` and with it the typing of `onFormSubmit`.
validationModeFormValidationModeonSubmitWhen the fields inside are validated. `validationMode` on an individual `Field.Root` takes precedence over this. - `onSubmit` — validate on submit, then re-validate on change. The default, and the right one for most forms: it does not tell someone their email is invalid while they are still on the third character of it. - `onBlur` — validate a field when it loses focus. - `onChange` — validate on every keystroke. Pair it with `validationDebounceTime` on the field if `validate` is expensive.

The generic is preserved, so <Form<SignUpValues> onFormSubmit={…}> types values for you. Everything else is a native <form> prop and passes straight through.