Forms
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.
import { form, defineResource, fields } from '@backlit/sdk'
import { z } from 'zod'
const orders = defineResource('orders', [
fields.text('customerName', { label: 'Customer' }),
])
const createOrder = orders.action(
'create',
z.object({ customerName: z.string() }),
() => {}
)
orders.view('create', () => {
const formBuilder = form(createOrder)
return formBuilder.setContent([
formBuilder.fields(...orders.pick('customerName')),
])
})
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "create",
"slots": {
"content": [
{
"kind": "form",
"target": {
"resource": "orders",
"action": "create"
},
"slots": {
"content": [
{
"kind": "form-fields",
"fields": [
{
"kind": "text",
"name": "customerName",
"label": "Customer"
}
]
}
]
}
}
]
}
}
}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.failwith 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.failwith 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.
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.
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.
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.
Pages of this category
| Page | Content |
|---|---|
| Form | The form builder: content, initial values, submit and clear |
| Form fields | A block of inputs, peer fields, and field roles |
| Conditions | Reveal and enable rules, with the list of operators |
| Repeater | Arrays of objects, row limits, and row conditions |