---
title: Forms
description: Collect values from a user and submit them to an action.
---

A form is a block that collects values and submits them to one action. You create a
form from the action, and not the reverse. The action has the schema, and the schema
is the single source of the types, the validation, and the error messages of the
form.

This introduction explains how a form, an action, and fields work together. The
pages of this category have the full API.

## A form starts from an action

An action validates a payload with a schema. When you call `form(action)`, the
builder reads the input type of that schema. TypeScript then checks each field name
that you add to the form, and each key of the initial values, against the schema. A
field that the action does not accept is a compile error.

The inputs come from fields. You select the fields of the resource that the form
must show, and each field renders with its `input` role. A text field becomes a text
input, an enum field becomes a select, and a date field becomes a date picker.

<BacklitExample path="form/basic" view="create" />

A form does not need one view for each purpose. A create view and an edit view
usually use the same fields with a different action, and the edit view supplies the
current record with `withInitialData`.

## Validation and errors

Validation runs on the server, in the action. The client sends the values, and the
action answers with a response. There are three types of failure, and the form
handles each one.

- When the payload fails the schema, the SDK returns an error response with
  status 422. Each schema issue has the path of its field, and the client shows the
  message next to that input.
- When your handler rejects some fields, call `ctx.fail` with an object of field
  names and messages. The client shows each message next to its input. Use this for
  a check that needs your data, such as an email address that is already in use.
- When the failure applies to the complete payload, call `ctx.fail` with text. The
  client shows the message for the form as a whole.

You write no client code for these cases. When the action succeeds, its response
decides the next step: a redirect, a refresh, or a notification. See
[Actions](/reference/views/action).

## Layout of a form

A form has a content slot, the same as a view. `form.fields` creates one block of
inputs, and you can put several of these blocks in panels or sections to give a long
form visible groups. Inside one block, `peers` puts related inputs on the same line,
such as a first name and a last name.

```ts
const builder = form(createCustomer)

builder.setContent([
  panel([
    builder
      .fields(...customers.pick('firstName', 'lastName', 'email'))
      .peers(['firstName', 'lastName']),
  ]).setTitle('Contact'),
  panel([builder.fields(...customers.pick('plan', 'seats'))]).setTitle('Subscription'),
])
```

## Conditions and repeaters

A condition shows or enables a part of the form from the current values, such as a
"company name" input that appears when the account type is "business". Conditions
are typed from the schema of the action, and they run in the client without a
request. A condition is a convenience for the user and not a security check. The
action must still validate the payload. See [Conditions](/reference/forms/conditions).

A repeater edits an array of objects in one form, such as the line items of an
invoice. The user adds and removes rows, and each row has the same fields. See
[Repeater](/reference/forms/repeater).

## Pages of this category

| Page                                         | Content                                                       |
| -------------------------------------------- | ------------------------------------------------------------- |
| [Form](/reference/forms/form)                 | The form builder: content, initial values, submit and clear   |
| [Form fields](/reference/forms/form-fields)   | A block of inputs, peer fields, and field roles               |
| [Conditions](/reference/forms/conditions)     | Reveal and enable rules, with the list of operators           |
| [Repeater](/reference/forms/repeater)         | Arrays of objects, row limits, and row conditions             |
