# Form

Validates fields and displays server errors.

```tsx
"use client"

import { useState } from "react"
import * as stylex from "@stylexjs/stylex"
import { Form } from "@/components/ui/form"
import { Field, FieldError, FieldGroup, FieldLabel } from "@/components/ui/field"
import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"

const styles = stylex.create({ form: { width: "20rem" } })

export default function FormDemo() {
  const [errors, setErrors] = useState<Record<string, string>>({})
  const [submitted, setSubmitted] = useState(false)
  return (
    <Form
      errors={errors}
      xstyle={styles.form}
      onFormSubmit={(values) => {
        if (values.username === "admin") {
          setErrors({ username: "This username is taken." })
          setSubmitted(false)
        } else {
          setErrors({})
          setSubmitted(true)
        }
      }}
    >
      <FieldGroup>
        <Field name="username">
          <FieldLabel>Username</FieldLabel>
          <Input required placeholder="Try admin" />
          <FieldError />
        </Field>
        <Button type="submit">Save</Button>
        {submitted && <output>Profile saved.</output>}
      </FieldGroup>
    </Form>
  )
}
```

## Installation

1. Install the following dependencies:

   ```bash
   npm install @base-ui/react @stylexjs/stylex
   ```

2. Set up the token layer and StyleX compiler from [Installation](https://carbon.style/docs/installation), including `state-styles.ts`.

3. Copy and paste the following code into your project.

   ```tsx title="components/ui/form.tsx"
   "use client"

   import type { CSSProperties } from "react"
   import { Form as FormPrimitive } from "@base-ui/react/form"
   import type { StyleXStyles } from "@stylexjs/stylex"
   import { stateStyles } from "@/lib/state-styles"

   function Form({
     xstyle,
     className,
     style,
     ...props
   }: Omit<FormPrimitive.Props, "className" | "style"> & {
     xstyle?: StyleXStyles
     className?: string
     style?: CSSProperties
   }) {
     return (
       <FormPrimitive
         data-slot="form"
         {...props}
         {...stateStyles(() => [xstyle], { className, style })}
       />
     )
   }
   export { Form }
   ```

4. Update the import paths to match your project setup.

## Usage

```tsx
import { Form } from "@/components/ui/form"
import { Field, FieldError, FieldLabel } from "@/components/ui/field"

import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"

;<Form onFormSubmit={(values) => console.log(values)}>
  <Field name="username">
    <FieldLabel>Username</FieldLabel>
    <Input required />
    <FieldError />
  </Field>
  <Button type="submit">Save</Button>
</Form>
```

## Anatomy

`Form` contains named `Field` controls and a submit button.

## Server errors

Pass server messages through `errors`, keyed by field name. Edit the field to clear its error. Submit `admin` in the demo to receive a simulated server error.

## API reference

Accepts [Base UI Form props](https://base-ui.com/react/components/form), including `render`, plus `xstyle`, `className` and inline `style`.

### Form

| Prop             | Type                                   | Default      |
| ---------------- | -------------------------------------- | ------------ |
| `errors`         | `Record<string, string \| string[]>`   | —            |
| `validationMode` | `"onSubmit" \| "onBlur" \| "onChange"` | `"onSubmit"` |
| `onFormSubmit`   | `(values, eventDetails) => void`       | —            |
| `actionsRef`     | `RefObject<Form.Actions \| null>`      | —            |

`onFormSubmit` receives valid values and prevents native navigation. Name each `Field` to include it in the submitted values.

### Data attributes

| Attribute          | On   | Effect       |
| ------------------ | ---- | ------------ |
| `data-slot="form"` | form | Form anatomy |
