# Form

> Validation for native forms.

Component · Forms · Pro kit · [Live page](https://ui.twentyfirst.media/pro/components/Form/)

Validation for native forms. Give `rules` by field `name`; on submit the form checks them, shows
each message under its field, marks the field `aria-invalid` and focuses the first one. After the
first submit, fields re-check as they change.

- Rules: `required`, `email`, `minLength`/`maxLength`, `min`/`max`, `pattern`, and `validate` for
  anything else. Messages can be set per rule.
- `onSubmit` receives the values by name; `errors` shows messages from the server.
- Works with `TextField`, `Input`, `Select`, `Textarea`, `SelectMenu`, `Checkbox` and `Switch`.

## Example

```tsx
import * as React from "react";
import {
  Button,
  Checkbox,
  Form,
  SelectMenu,
  TextField,
  Textarea,
  toast,
} from "@twentyfirstmedia/pro";

export default function Preview() {
  return (
    <div className="tf-panel" style={{ maxWidth: 520 }}>
      <Form
        rules={{
          name: { required: "Tell us your name" },
          email: { required: true, email: true },
          team: { required: "Pick a team" },
          message: { minLength: 20, message: "Write at least 20 characters" },
          terms: { required: "Accept the terms to continue" },
        }}
        onSubmit={(v) => toast({ text: `Thanks, ${v.name}` })}
      >
        <TextField name="name" label="Name" placeholder="Mara Ellis" required />
        <TextField
          name="email"
          label="Work email"
          type="email"
          placeholder="you@company.com"
          required
        />
        <SelectMenu
          name="team"
          label="Team"
          placeholder="Choose a team"
          required
          options={["Design", "Engineering", "Growth", "Finance"]}
        />
        <Textarea name="message" label="Message" placeholder="What do you need?" rows={3} />
        <Checkbox name="terms" value="yes">
          I accept the terms
        </Checkbox>
        <div className="tf-row" style={{ justifyContent: "flex-end" }}>
          <Button type="submit">Send</Button>
        </div>
      </Form>
    </div>
  );
}
```

## Props

### Form

| Prop | Type | Notes |
| --- | --- | --- |
| `rules?` | `Record<string, FormRule>` | Rules by field `name`. Fields show their message under the input. |
| `onSubmit?` | `(values: FormValues) => void` | Called with the values (by `name`) when every rule passes. |
| `onInvalid?` | `(errors: Record<string, string>) => void` | Called with the messages when the form is submitted with errors. |
| `errors?` | `Record<string, string>` | Messages from the server, by field name (for example after a failed save). |
| `children?` | `ReactNode` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### TextField

| Prop | Type | Notes |
| --- | --- | --- |
| `type?` | `string` | Input type (`"text"` by default): `"email"`, `"number"`, `"tel"`, `"url"`, `"password"` … |
| `icon?` | `IconName` |  |
| `suffix?` | `ReactNode` |  |
| `value?` | `string` |  |
| `defaultValue?` | `string` |  |
| `placeholder?` | `string` |  |
| `disabled?` | `boolean` |  |
| `readOnly?` | `boolean` |  |
| `autoComplete?` | `string` |  |
| `autoFocus?` | `boolean` |  |
| `min?` | `number \| string` | Smallest value for `type="number"`, `"date"` and the like (native `min`). |
| `max?` | `number \| string` | Largest value (native `max`). |
| `step?` | `number \| string` | Step between valid values (native `step`), e.g. `1` for whole numbers or `"any"`. |
| `minLength?` | `number` | Fewest characters (native `minlength`). |
| `maxLength?` | `number` | Most characters (native `maxlength`). |
| `pattern?` | `string` | Pattern the value must match (native `pattern`). |
| `inputMode?` | `"none" \| "text" \| "tel" \| "url" \| "email" \| "numeric" \| "decimal" \| "search"` | Virtual keyboard on touch devices (native `inputmode`), e.g. `"numeric"` or `"decimal"`. |
| `onChange?` | `(e: ChangeEvent<HTMLInputElement>) => void` |  |
| `onBlur?` | `(e: ChangeEvent<HTMLInputElement>) => void` |  |
| `onKeyDown?` | `(e: KeyboardEvent<HTMLInputElement>) => void` |  |
| `action?` | `ReactNode` | An interactive control at the end of the field (an `IconButton`: clear, copy, locate …). Unlike `suffix` it can be clicked, and it stays when the field shows an error or success mark. |
| `reveal?` | `boolean` | For `type="password"`: a button that shows and hides the password (default true). |
| `label?` | `string` |  |
| `hint?` | `string` |  |
| `error?` | `string` |  |

### SelectMenu

| Prop | Type | Notes |
| --- | --- | --- |
| `options` | `(string \| SelectMenuOption)[]` | Required |
| `value?` | `string` |  |
| `defaultValue?` | `string` |  |
| `onChange?` | `(value: string) => void` |  |
| `placeholder?` | `string` |  |
| `disabled?` | `boolean` |  |
| `size?` | `"sm" \| "md"` | `sm`: a compact trigger, e.g. a sort menu next to a heading. |
| `label?` | `string` |  |
| `hint?` | `string` |  |
| `error?` | `string` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### Textarea

| Prop | Type | Notes |
| --- | --- | --- |
| `placeholder?` | `string` |  |
| `value?` | `string` |  |
| `defaultValue?` | `string` |  |
| `rows?` | `number` |  |
| `disabled?` | `boolean` |  |
| `onChange?` | `(e: ChangeEvent<HTMLTextAreaElement>) => void` |  |
| `label?` | `string` |  |
| `hint?` | `string` |  |
| `error?` | `string` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### Checkbox

| Prop | Type | Notes |
| --- | --- | --- |
| `name?` | `string` |  |
| `value?` | `string` |  |
| `required?` | `boolean` |  |
| `checked?` | `boolean` |  |
| `defaultChecked?` | `boolean` |  |
| `onChange?` | `(e: ChangeEvent<HTMLInputElement>) => void` |  |
| `children?` | `ReactNode` |  |
| `disabled?` | `boolean` |  |
| `label?` | `string` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### Button

| Prop | Type | Notes |
| --- | --- | --- |
| `variant?` | `"primary" \| "secondary" \| "soft" \| "ghost" \| "danger" \| "danger-solid"` |  |
| `size?` | `"md" \| "sm"` |  |
| `icon?` | `IconName` |  |
| `iconRight?` | `IconName` |  |
| `disabled?` | `boolean` |  |
| `type?` | `"button" \| "submit" \| "reset"` |  |
| `onClick?` | `(e: MouseEvent<HTMLButtonElement>) => void` |  |
| `children?` | `ReactNode` |  |
| `asChild?` | `boolean` | Render the single child element (a link, a router Link) with the button's look instead of a <button>. |
| `id?` | `string` |  |
| `name?` | `string` | Form field name and value, sent with the form when this button submits it. |
| `value?` | `string` |  |
| `form?` | `string` | The id of the form this button belongs to, when it sits outside it. |
| `title?` | `string` |  |
| `tabIndex?` | `number` |  |
| `autoFocus?` | `boolean` |  |
| `aria-label?` | `string` |  |
| `aria-labelledby?` | `string` |  |
| `aria-describedby?` | `string` |  |
| `aria-expanded?` | `boolean \| "true" \| "false"` | For disclosure and menu triggers: whether what the button controls is open. |
| `aria-controls?` | `string` |  |
| `aria-haspopup?` | `boolean \| "true" \| "false" \| "menu" \| "listbox" \| "tree" \| "grid" \| "dialog"` |  |
| `aria-pressed?` | `boolean \| "true" \| "false" \| "mixed"` | For toggle buttons. |
| `aria-current?` | `boolean \| "true" \| "false" \| "page" \| "step" \| "location" \| "date" \| "time"` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |
