Action target
Submit a small action directly or through a dialog.
Use submitTo when an action needs only a button, a confirmation, or a small
fixed set of fields.
API
submitTo(action, args?, presentation?)
.withInitialData(values)
.setDialog(dialog)
.setFields(fields)
Pass the action definition directly. submitTo does not accept a thunk.
args must contain one defined value for each action parameter.
presentation can be a value or a callback. It supports text, icon,
tooltip, skip, disabled, intent, and primary.
skip: trueremoves the complete action.disabled: truesends only a disabled control. Backlit does not resolve args, dialog data, or form data for it.
Missing args on an active action are an authoring error.
Direct action
Do not set a dialog or fields. The renderer sends an empty payload when the person selects the action. It does not mount an HTML form or create RHF state.
submitTo(archiveOrder, [order.id], { text: 'Archive' })
Confirmation dialog
Use setDialog to ask for confirmation. A fieldless confirmation also sends
an empty payload and does not create RHF state.
submitTo(cancelOrder, [order.id], { text: 'Cancel order' }).setDialog({
title: 'Cancel this order?',
description: 'This action cannot be undone.',
submitLabel: 'Cancel order',
})
Dialog with fields
Call setFields after setDialog. The field list is stable. Each field can
use its normal configuration and can read the current row. Initial values use
the same input remapping as a regular form.
submitTo(changeStatus, [order.id], { text: 'Change status' })
.withInitialData({ status: order.status })
.setDialog({
title: 'Change order status',
submitLabel: 'Save status',
})
.setFields(orders.pick('status'))
The dialog mounts the regular form renderer only while it is open. This keeps all RHF behavior in one place.
submitTo does not accept panels, sections, conditions, zones, or a dynamic
field list. For a full form, create a view with form() and open that view
with visitTo in modal or drawer mode.
Intent and priority
Use intent: 'destructive' when the action removes data that cannot be restored.
Other actions use neutral. Intent describes the effect of an action.
Use primary: true to mark the main action. These values are presentation;
authorize and validate the operation on the server.
Complete controls
import {
callout,
defineResource,
fields,
linkTo,
panel,
submitTo,
table,
visitTo,
} from '@backlit/sdk'
import { z } from 'zod'
const orders = defineResource('orders', [
fields.text('id'),
fields.text('title'),
])
const detail = orders.view('detail', ['id'], (ctx) =>
callout(`Order ${ctx.paramValues.id}`)
)
const archive = orders.action(
'archive',
['id'],
z.object({}),
(ctx) => ctx.refresh()
)
const rename = orders.action(
'rename',
['id'],
z.object({ title: z.string().min(1) }),
(ctx) => ctx.notify(ctx.data.title)
)
orders.view('list', () =>
panel([
table([{ id: '42', title: 'Notebook' }])
.setFields(orders.pick('title'))
.onRowClick(linkTo(detail, (row) => [row.id]))
.setRowActions([
visitTo(detail, (row) => [row.id], {
text: 'Open',
mode: 'drawer',
}),
submitTo(
archive,
(row: { id: string }) => [row.id],
{
text: 'Archive',
intent: 'destructive',
}
).setDialog({
title: 'Archive this order?',
submitLabel: 'Archive',
}),
submitTo(
rename,
(row: { id: string }) => [row.id],
{
text: 'Rename',
}
)
.setDialog({ title: 'Rename order' })
.setFields(orders.pick('title')),
]),
]).setActions([
visitTo(detail, ['42'], {
text: 'Open order',
mode: 'modal',
}),
submitTo(rename, ['42'], {
text: 'Rename order',
primary: true,
})
.withInitialData({ title: 'Notebook' })
.setDialog({ title: 'Rename order' })
.setFields(orders.pick('title')),
])
)
export default orders{
"kind": "success",
"status": 200,
"node": {
"kind": "view",
"resource": "orders",
"name": "list",
"slots": {
"content": [
{
"kind": "panel",
"actions": [
{
"kind": "visit",
"resource": "orders",
"view": "detail",
"mode": "modal",
"args": [
"42"
],
"text": "Open order"
},
{
"kind": "action",
"form": {
"kind": "form",
"target": {
"resource": "orders",
"action": "rename",
"args": [
"42"
]
},
"slots": {
"content": [
{
"kind": "form-fields",
"fields": [
{
"kind": "text",
"name": "title",
"label": ""
}
]
}
]
},
"initial": {
"title": "Notebook"
}
},
"text": "Rename order",
"primary": true,
"dialog": {
"title": "Rename order"
}
}
],
"slots": {
"content": [
{
"kind": "table",
"fields": [
{
"kind": "text",
"name": "title",
"label": ""
}
],
"targets": [
{
"kind": "link",
"resource": "orders",
"view": "detail"
},
{
"kind": "visit",
"resource": "orders",
"view": "detail",
"mode": "drawer"
},
{
"kind": "action",
"form": {
"kind": "form",
"target": {
"resource": "orders",
"action": "archive"
},
"slots": {
"content": []
}
}
},
{
"kind": "action",
"form": {
"kind": "form",
"target": {
"resource": "orders",
"action": "rename"
},
"slots": {
"content": [
{
"kind": "form-fields",
"fields": [
{
"kind": "text",
"name": "title",
"label": ""
}
]
}
]
}
}
}
],
"data": [
{
"title": "Notebook",
"$click": {
"target": 0,
"args": [
"42"
]
},
"$actions": [
{
"target": 1,
"args": [
"42"
],
"text": "Open"
},
{
"target": 2,
"text": "Archive",
"intent": "destructive",
"dialog": {
"title": "Archive this order?"
},
"form": {
"target": {
"args": [
"42"
]
},
"submit": {
"label": "Archive"
}
}
},
{
"target": 3,
"text": "Rename",
"dialog": {
"title": "Rename order"
},
"form": {
"target": {
"args": [
"42"
]
},
"initial": {
"title": "Notebook"
}
}
}
]
}
]
}
]
}
}
]
}
}
}