Form
Lays out a form, with an optional title, description and footer, and wires up submit, loading and disabled states. Field state and validation stay with your app or form library.JSX
<Form
title="Create account"
description="Enter your details."
loadingText="Saving…"
onSubmit={save}
footer={
<>
<Button variant="outline">Cancel</Button>
<Form.Submit>Save</Form.Submit>
</>
}
>
<Field label="Name">
<Input placeholder="Ada Lovelace" />
</Field>
<Field label="Email">
<Input inputMode="email" placeholder="ada@example.org" />
</Field>
</Form>Installation
Package
CLI (copy source)
pnpm
pnpm add @advui/corenpm
npm install @advui/coreUsage
import { Button, Form, Field, Input } from '@advui/core'
const [saving, setSaving] = useState(false)
const save = async () => {
setSaving(true)
try {
await saveUser()
} finally {
setSaving(false)
}
}
<Form
title="Create account"
description="Enter your details."
onSubmit={save}
loading={saving}
loadingText="Saving…"
footer={
<>
<Button variant="outline">Cancel</Button>
<Form.Submit>Save</Form.Submit>
</>
}
>
<Field label="Name">
<Input />
</Field>
<Field label="Email">
<Input inputMode="email" />
</Field>
</Form>Examples
Basic
Fields stacked with a consistent gap.Preview
Code
Title and description
Preview
Code
Loading
The app sets `loading` around the request. Press Save several times: presses while saving are ignored.Preview
Code
Horizontal
A compact search form in one row. Give the input `flex` to share the row.Preview
Code
Disabled
Preview
Code
With your own validation
The app (or React Hook Form, Formik…) owns values and errors; Field shows them.Preview
Code
Custom styling
Style props and themes work as on any view.Preview
Code
API reference
Form
A `<form>` on web and a View on native, built on Tamagui’s Form. It takes every view prop (`padding`, `backgroundColor`, `borderRadius`, `width`, `theme`, media props, `testID`, `aria-*`…). It never clones or changes its children.| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | The fields: Field, inputs, checkboxes, your own components… |
gap | SpaceTokens | number | '4' | Space between the fields. |
title | ReactNode | — | Text becomes a level-2 heading that names the form. Pass an element (e.g. `<Heading level={1}>`) for another level. |
description | ReactNode | — | Muted text under the title; describes the form. |
footer | ReactNode | — | Actions under the fields, right-aligned. Put anything here: Cancel, `Form.Submit`, links. No submit button is assumed. |
onSubmit | () => void | Promise<unknown> | — | Called by `Form.Submit` and, on web, by Enter in a field. Not called while `disabled` or `loading`. A returned Promise is not awaited: set `loading` yourself. |
loading | boolean | false | The app is submitting. `Form.Submit` shows a spinner and is busy, and `onSubmit` is blocked. Fields stay editable. |
loadingText | ReactNode | — | Replaces the `Form.Submit` label while loading, e.g. "Saving…", and is announced once on web. |
disabled | boolean | false | Disables every form control inside, in a Field or not (Input, Textarea, Select, Checkbox, Switch, Radio Group, pickers…), and `Form.Submit`, and blocks `onSubmit`. Other buttons, such as Cancel, stay enabled. |
direction | 'vertical' | 'horizontal' | 'vertical' | `horizontal` puts the fields in a wrapping, bottom-aligned row: for search bars and filters. |
fullWidth | boolean | false | The form fills its container, and footer actions stack at full width. Fields fill the width in either case. |
Form.Submit
A Loading Button that submits the form: a submit button on web (so Enter in a field submits too), and a press that calls `onSubmit` on native. Takes every Loading Button prop.| Prop | Type | Default | Description |
|---|---|---|---|
loading | boolean | the form's `loading` | Spinner, `aria-busy` and blocked presses. |
loadingText | ReactNode | the form's `loadingText` | Label while loading. |
disabled | boolean | false | Also disabled while the form is. |
useParentForm
Reads the surrounding Form, for your own fields and actions; returns a `FormContextValue`. Outside a Form it returns the defaults, and `submit` does nothing. It was called `useFormStatus` (still exported, deprecated), which is also the name of a React DOM hook for Server Actions.| Prop | Type | Default | Description |
|---|---|---|---|
disabled | boolean | — | The form's `disabled`. |
loading | boolean | — | The form's `loading`. |
loadingText | ReactNode | — | The form's `loadingText`. |
submit | () => void | — | Calls `onSubmit` unless disabled or loading, e.g. from a custom button or `onSubmitEditing` on native. |
Accessibility
- On web it is a
<form>. With atitleit is named by it (aria-labelledby) and described bydescription, so screen-reader users can jump to it as a form landmark. Without a title, passaria-labelif it should be a landmark. - A text
titleis a heading (level 2,headerrole on iOS and Android); pass your own Heading for another level. - Enter in a field submits on web, as in any HTML form with a submit button. On native, call
submitfromuseParentForm()inonSubmitEditingif Return should submit. - While loading,
Form.Submitis busy (aria-busy) and disabled, andloadingTextis read once from a polite status region on web. The form itself is not marked busy, so its fields stay readable. - While disabled, every form control inside is disabled (
aria-disabledand not editable), and Field labels are dimmed. Form never clones its children: the core controls read the form through context, and your own controls can calluseFieldControl(props)oruseParentForm(). Buttons other thanForm.Submitstay enabled, so Cancel still works. - Browser validation is off (
noValidate) so errors come from your app, the same on every platform: show them with a Field’serror.
| Key | Action |
|---|---|
| Enter | In a field: submits the form (web). |
| Enter / Space | On Form.Submit: submits; ignored while loading or disabled. |
| Tab | Moves through the fields and actions in order. |
Responsive behavior
Vertical forms fill their container and stack fields. Horizontal forms wrap fields to the next line when they run out of room; give fields flex and minWidth. Use flat values (padding="4 sm:6") for per-breakpoint styles.
Platform notes
Web
Renders
<form noValidate>; Form.Submit is <button type="submit">.iOS
No form element:
Form.Submit calls onSubmit on press. The loading status is read from the busy button.Android
Same as iOS.