Build Your WorkspaceViews
Form Views
Configure edit forms — sections, sidebar, tabs, grid layouts, and reactive visibility.
Form views control the edit interface for collections and globals. Configure them with .form().
Basic Form
.form(({ v, f }) => v.collectionForm({}))Without config, the form renders all fields in a single column.
Sections
Group fields into labeled sections:
.form(({ v, f }) =>
v.collectionForm({
fields: [
{
type: "section",
label: { en: "Contact Information" },
layout: "grid",
columns: 2,
fields: [f.name, f.email, f.phone],
},
{
type: "section",
label: { en: "Profile" },
fields: [f.bio],
},
{
type: "section",
label: { en: "Services" },
fields: [f.services],
},
],
}),
)Section Options
| Option | Type | Description |
|---|---|---|
type | "section" | Required |
label | string | i18n | Section heading |
description | string | i18n | Section description |
layout | "grid" | "stack" | Field layout |
columns | number | Grid columns (with layout: "grid") |
fields | Field[] | Fields in this section |
Sidebar
Place fields in a sidebar panel:
.form(({ v, f }) =>
v.collectionForm({
sidebar: {
position: "right",
fields: [f.isActive, f.avatar, f.status],
},
fields: [
// Main content sections...
],
}),
)Computed Fields
Auto-compute field values from other fields:
.form(({ v, f }) =>
v.collectionForm({
fields: [
{
type: "section",
fields: [
f.name,
{
field: f.slug,
compute: {
handler: ({ data }) => {
if (data.name && !data.slug) {
return slugify(data.name);
}
return undefined;
},
deps: ({ data }) => [data.name, data.slug],
debounce: 300,
},
},
],
},
],
}),
)| Option | Type | Description |
|---|---|---|
handler | (ctx) => value | Compute function |
deps | (ctx) => any[] | Reactive dependencies |
debounce | number | Debounce in milliseconds |
Conditional Visibility
Show or hide fields based on other field values:
.form(({ v, f }) =>
v.collectionForm({
fields: [
{
type: "section",
fields: [
f.cancelledAt,
{
field: f.cancellationReason,
hidden: ({ data }) => data.status !== "cancelled",
},
],
},
],
}),
)See Visibility for more patterns.
Real-World Example
From the barbershop — barbers collection with sidebar, grid layout, sections, and computed slug:
collections/barbers.ts
.form(({ v, f }) =>
v.collectionForm({
sidebar: {
position: "right",
fields: [f.isActive, f.avatar],
},
fields: [
{
type: "section",
label: { en: "Contact Information" },
layout: "grid",
columns: 2,
fields: [
f.name,
{
field: f.slug,
compute: {
handler: ({ data }) => {
if (data.name && !data.slug?.trim()) {
return slugify(data.name);
}
return undefined;
},
deps: ({ data }) => [data.name, data.slug],
debounce: 300,
},
},
f.email,
f.phone,
],
},
{
type: "section",
label: { en: "Profile" },
fields: [f.bio],
},
{
type: "section",
label: { en: "Services" },
fields: [f.services],
},
{
type: "section",
fields: [f.socialLinks],
},
{
type: "section",
fields: [f.workingHours],
},
],
}),
)Related Pages
- List Views — Table configuration
- Visibility — Reactive visibility rules
- Fields — Field types