# Forms

Compose labels, validation, submission, and reset with Form, Field, and the kit’s controls.

## Start with a field

Use [Form](/docs/components/form/), [Field](/docs/components/field/), and [Input](/docs/components/input/) for a conventional form. Install Input for Field’s source. FieldLabel, FieldDescription, and FieldError connect the control to its accessible name, help, and validation feedback.

Sign-in form with field validation

[Complete TSX file](/examples/form/default.tsx)

```tsx
"use client";

import { Button } from "@/siteplane/components/button";
import { Field, FieldError, FieldLabel } from "@/siteplane/components/field";
import { Form } from "@/siteplane/components/form";
import { Input } from "@/siteplane/components/input";

export default function Example() {
  return (
    <Form
      className="grid w-full max-w-sm gap-4"
      onSubmit={(event) => event.preventDefault()}
    >
      <Field name="email">
        <FieldLabel>Email</FieldLabel>
        <Input
          type="email"
          autoComplete="email"
          placeholder="you@example.com"
          required
        />
        <FieldError>Enter a valid email address.</FieldError>
      </Field>
      <Field name="password">
        <FieldLabel>Password</FieldLabel>
        <Input type="password" autoComplete="current-password" required />
        <FieldError>Enter your password.</FieldError>
      </Field>
      <Button type="submit">Sign in</Button>
    </Form>
  );
}
```

## Choose how values are owned

For an uncontrolled text input, set `defaultValue` and a field `name`, then read `new FormData(event.currentTarget)` on submit. For a controlled input, set `value` and update it synchronously in `onChange`. Control-specific callbacks differ: Switch uses `onCheckedChange`, Select uses `onValueChange`, and calendar/date wrappers have their own documented value types.

Do not pass both value and defaultValue. Reset an uncontrolled field with the native form reset event. For controlled fields, reset application state in `onReset`; the browser cannot reset a React-owned value by itself.

## Validation and submission

Use the control’s required, type, min/max, or length constraints where supported. Show asynchronous or server errors with Form’s `errors` prop and keep submitted values on failure; [Server validation](/docs/components/form/#server-validation) shows a request that returns a field error. Prevent default submission only when your application handles it. Disable duplicate submit actions while an operation is pending and provide a visible status when it settles.

Hidden inputs do not all validate alike. ColorPicker serializes hex through a hidden input; required does not make that hidden input block submission. ColorSwatchPicker has a visually hidden validation input. Read the specific control’s form notes rather than assuming every wrapper behaves like a native text input.

## Related controls

Use [Fieldset](/docs/components/fieldset/) to name a group, [CheckboxGroup](/docs/components/checkbox-group/) for several choices, and [RadioGroup](/docs/components/radio-group/) for a single visible choice. [SettingsList](/docs/components/settings-list/) connects a setting’s title/description to a supplied control without owning its business state.

## Complete application

[Team settings](/docs/examples/team-settings/) includes controlled inputs, selection, switches, local validation, and reset to the last saved values. Copy its complete file after the [one-time setup](/docs/installation/). Replace its local save handler with your service and preserve error/reset behavior; no API request is hidden in the example.
