Tessina UI
ConfiguratorGitHubIntroduction
InstallationUsageTheming
ComponentsAccordionAction SheetAlertAlertDialogArea ChartAspectRatioAvatarBadgeBannerBar ChartBottom NavBreadcrumbButtonButtonGroupCalendarCardCarouselChartChatBubbleCheckboxChipCodeBlockCollapsibleColor PickerComboboxCommandContainerContextMenuDate PickerDividerDrawerDropdown MenuEmptyStateFABFieldFieldsetFile UploadFile Upload 2FlexFormGridHoverCardIconButtonLabelLine ChartLinkMenubarMeterModalNavigation MenuNumberFieldOTP InputPaginationPie ChartPopoverProgressPromptInputRadar ChartRadial ChartRadioRatingScroll AreaSearchSegmentedControlSelectShortcutSidebarSkeletonSliderSpacerSpinnerSplit ButtonStackStatusStepperSurfaceSwitchTableTabsTextareaTime PickerToastToggleButtonToggleGroupToolbarTooltipTop Header DesktopTop Header Mobile
Contributing
Components

Form

A complete form layout — header, body, sections, rows, footer, submit error banner — built on Base UI's Form primitive with four variants, five sizes, intent accents, validation modes, and full RTL support.

Playground

Installation

pnpm add @tessinaui/ui

Usage

import {
  FormRoot,
  FormHeader,
  FormTitle,
  FormDescription,
  FormBody,
  FormSection,
  FormRow,
  FormDivider,
  FormFooter,
  FormSubmitError,
  FormHelperText,
} from "@tessinaui/ui";
<FormRoot
  variant="outline"
  onFormSubmit={(values) => save(values)}
  validationMode="onBlur"
>
  <FormHeader>
    <FormTitle>Edit profile</FormTitle>
    <FormDescription>Update your public information.</FormDescription>
  </FormHeader>

  <FormBody>
    <FormRow>
      <Field name="firstName" label="First name" required />
      <Field name="lastName"  label="Last name"  required />
    </FormRow>
    <Field name="email" label="Email" type="email" required />
    <Switch label="Email me product updates" defaultChecked />
  </FormBody>

  <FormFooter>
    <Button variant="ghost">Cancel</Button>
    <Button type="submit">Save changes</Button>
  </FormFooter>
</FormRoot>

Examples

Default

A profile form with a header, a two-up name row, an email field, and a footer.

Variants

Four visual treatments — ghost (structure only), outline, filled, and elevated.

Sizes

Five sizes from xs to xl scale the title, padding, gaps, and footer spacing together.

Sections

Group related fields with FormSection, FormRow, and FormDivider inside a single form.

Submit error

FormSubmitError shows a tinted, bordered banner with role="alert" for top-level errors.

Loading

FormSkeleton reserves the form's chrome, header, fields, and footer while data loads.

When to use

Form is the top-level container for any form-shaped interaction in your app — sign-in, sign-up, profile editing, settings panes, multi-section onboarding. It bundles:

  • Visual chrome (variants, padding, intent border accent)
  • Layout primitives (Header, Body, Section, Row, Footer)
  • Submission state (isSubmitting disables everything and sets aria-busy)
  • Server-side error reporting (errors map keyed by field name, plus a SubmitError banner for top-level errors)

For a single grouped set of controls without form-level submission, use Fieldset. For an individual labeled input, use Field.

API Reference

FormRoot props

PropTypeDefaultDescription
size"xs" | "sm" | "md" | "lg" | "xl""md"Scales title, padding, gap, footer spacing
variant"ghost" | "outline" | "filled" | "elevated""ghost"Visual treatment — ghost is just structure, the others wrap everything in a card
rounded"none" | "sm" | "md" | "lg" | "full""md"Card corner radius (only applies to non-ghost variants)
intent"none" | "primary" | "error" | "warning" | "success" | "info""none"Drives border accent and helper text colour
dir"ltr" | "rtl""ltr"Text direction
layout"vertical" | "horizontal""vertical"Default Field label layout (Field components read this from context)
validationMode"onSubmit" | "onBlur" | "onChange""onSubmit"When fields validate. Field.Root's own validationMode always wins
errorsRecord<string, string | string[]>—Server-side errors keyed by field name. Connect from your form action handler
onFormSubmit(values, eventDetails) => void | Promise<void>—Submit handler with parsed form values. Calls preventDefault() on the native submit event automatically
actionsRefRefObject<{ validate(name?) }>—Imperative validation — actionsRef.current.validate() runs all, validate('email') runs one
isSubmittingbooleanfalseDisables the form and sets aria-busy="true"
disabledbooleanfalseDisables every form control inside (cascades natively via an internal <fieldset>)

FormHeader / Title / Description

FormHeader is a flex column wrapper. FormTitle renders an <h2> by default (configurable via level). FormDescription renders a muted <p> below the title.

FormBody props

A flex column with size-aware gap between children. Drop Field, Switch, Fieldset, FormSection, FormRow, etc. inside.

FormSection props

PropTypeDescription
titleReactNodeOptional section title (renders as <h3>)
descriptionReactNodeOptional muted helper text below the title

A semantic <section> block grouping related fields under their own title and description. Use it for thematic grouping inside a form (e.g. "Profile" / "Notifications" / "Permissions") when you don't want full Fieldset chrome.

FormRow props

PropTypeDefaultDescription
stackOnMobilebooleantrueStacks children vertically below the sm breakpoint, then switches to a row at sm+. Set false for always-horizontal layouts

Lays children out side-by-side with flex: 1 so each takes equal width.

FormFooter props

PropTypeDefaultDescription
align"start" | "center" | "end" | "between""end"Horizontal alignment of footer children

Adds size-aware top spacing and gap. Drop Buttons, Links, or any node here.

FormSubmitError props

PropTypeDefaultDescription
intentFormIntent"error"Colour palette and default icon
titleReactNode—Bold title above the body text
hideIconbooleanfalseRender without the leading icon

A bordered, tinted banner for top-level form errors (e.g. "Couldn't sign in"). Sets role="alert" for screen readers.

FormHelperText props

PropTypeDefaultDescription
intentFormIntentinheritedOverride the helper text colour for this instance only
leadingIconReactNode—Icon rendered before the text

A small subtle line below the form (terms, fine print, "all changes save automatically", etc).

FormDivider

A 1px horizontal separator with size-aware vertical spacing — use between major sections inside a long form.

Composition tips

  • FormRow is for putting two short fields side-by-side (e.g. first/last name). For full vertical stacks, just use FormBody directly.
  • FormSection and Fieldset overlap — FormSection is a lighter weight semantic group (no <fieldset> element, no disabled cascade), Fieldset is the real form-grouping primitive with native disabled propagation.
  • The submit handler receives parsed form values via Base UI's typed callback. To handle async server validation, return a Promise and surface results through errors.
  • Keep cognitive load down (NN/g): chunk fields into FormSections, defer optional fields behind a Collapsible, and put primary action on the right (LTR) or left (RTL).

Notes

  • Built on @base-ui/react/form. Errors flow through Base UI's FormContext to descendant Field.Roots — set name on each Field that should map to a server error key.
  • The disabled prop wraps children in an internal <fieldset disabled> so every native form control inside gets the disabled state for free.
  • For multi-step forms, render multiple FormRoots and switch between them with state — each step gets its own onFormSubmit.

Flex

A low-level flexbox layout primitive that exposes the full flex API — four directions, three wrap modes, independent row and column gap, align-items, justify-content, align-content, inline mode, polymorphic render, and LTR/RTL. Ships with FlexItem for per-child grow, shrink, basis, order, and alignSelf control.

Grid

A CSS-grid layout primitive with static and responsive column counts, gap presets, flow control, and per-cell placement via GridItem. Polymorphic render, RTL, and no hard-coded tokens.

On this page

PlaygroundInstallationUsageExamplesDefaultVariantsSizesSectionsSubmit errorLoadingWhen to useAPI ReferenceFormRoot propsFormHeader / Title / DescriptionFormBody propsFormSection propsFormRow propsFormFooter propsFormSubmitError propsFormHelperText propsFormDividerComposition tipsNotes