Layout Fields
Tabs
The f.tabs() layout field groups fields into tabbed panels. Tabs are UI-only -- they do not affect data storage. All fields inside tabs are flattened to the parent level in the database.
Basic usage
import { f, defineVextroCollection } from "vextro";
export const pages = defineVextroCollection({
slug: "pages",
label: "Pages",
collectionType: "content",
tableName: "pages",
fields: {
slug: f.slug({ required: true }),
mainContent: f.tabs({
tabs: [
{
label: "Content",
fields: {
title: f.text({ required: true }),
body: f.richText(),
},
},
{
label: "SEO",
fields: {
metaTitle: f.text(),
metaDescription: f.textarea(),
},
},
],
}),
},
}); Here title, body, metaTitle, and metaDescription are stored as top-level document fields. The tabs only affect the editor layout.
Options
| Option | Type | Default | Description |
|---|---|---|---|
tabs | Array<TabDefinition> | required | Array of tab objects with label and fields. |
defaultTab | number | 0 | Zero-based index of the initially active tab. |
condition | FieldCondition | -- | Condition for showing the entire tabs section. |
Each tab accepts:
| Option | Type | Default | Description |
|---|---|---|---|
label | string | required | Display label for the tab. |
description | string | -- | Description shown inside the tab panel. |
fields | Record<string, VextroFieldInput> | required | Fields to render in this tab. |
condition | FieldCondition | -- | Condition for showing this individual tab. |
Conditional tabs
Individual tabs can be conditionally shown based on other field values:
mainContent: f.tabs({
tabs: [
{ label: "Content", fields: { title: f.text(), body: f.richText() } },
{
label: "Download Options",
condition: { field: "pageType", equals: "download" },
fields: { downloadUrl: f.url(), fileSize: f.text() },
},
],
}), Data storage
Tabs do not create nested objects. Field names must be unique across all tabs in the same f.tabs() call.