Page Page protocol schemas
Page Region Schema
A named region in the template where components are dropped.
Source: packages/spec/src/ui/page.zod.ts
import { ElementDataSourceSchema, InterfacePageConfigSchema, PageSchema, PageComponentSchema, PageComponentType, PageRegionSchema, PageTypeSchema, PageVariableSchema } from '@objectstack/spec/ui' ;
import type { ElementDataSource, InterfacePageConfig, Page, PageComponent, PageComponentType, PageRegion, PageType, PageVariable } from '@objectstack/spec/ui' ;
// Validate data
const result = ElementDataSourceSchema. parse (data);
Property Type Required Description object string✅ Object to query view stringoptional Named view to apply filter anyoptional Additional filter criteria sort { field: string; order: Enum<'asc' | 'desc'> }[]optional Sort order limit integeroptional Max records to display
Interface-level page configuration (Airtable parity)
Property Type Required Description source stringoptional Source object name for the page columns string[] | { field: string; label?: string | Record<string, string>; width?: number; align?: Enum<'left' | 'center' | 'right'>; … }[]optional Columns shown by the page. Blank = all object fields. Defined directly on the page (no view inheritance). sort { field: string; order: Enum<'asc' | 'desc'> }[]optional Default sort order for the page, defined directly on the page. filterBy { field: string; operator: Enum<'equals' | 'not_equals' | 'contains' | 'not_contains' | 'starts_with' | … +14 more>; value?: string | number | boolean | null | (string | number)[] }[]optional Always-on page filter (base filter). levels integeroptional Number of hierarchy levels to display sourceView stringoptional @deprecated Legacy named-view inheritance. Define columns/sort/filterBy on the page instead. appearance { showDescription: boolean; allowedVisualizations?: Enum<'grid' | 'kanban' | 'gallery' | 'calendar' | 'timeline' | 'gantt' | 'map' | 'chart' | 'tree'>[] }optional Appearance and visualization configuration userFilters { element: Enum<'dropdown' | 'tabs' | 'toggle'>; fields?: object[]; tabs?: object[]; showAllRecords?: boolean; … }optional End-user quick-filter bar for this page (overrides the source view's userFilters) userActions { sort: boolean; search: boolean; filter: boolean; refresh: boolean; … }optional User action toggles addRecord { enabled: boolean; position: Enum<'top' | 'bottom' | 'both'>; mode: Enum<'inline' | 'form' | 'modal'>; formView?: string }optional Add record entry point configuration buttons string[]optional Toolbar buttons — names of the source object's actions to surface in the page toolbar recordAction Enum<'drawer' | 'page' | 'modal' | 'none'>optional How clicking a record opens its detail (drawer | page | modal | none). Default: drawer showRecordCount booleanoptional Show record count at page bottom allowPrinting booleanoptional Allow users to print the page
Property Type Required Description name string✅ Page unique name (lowercase snake_case) label string | Record<string, string>✅ Display label — the default-language string, or an inline locale map ({ en, "zh-CN" }) resolved at render time description string | Record<string, string>optional Display label — the default-language string, or an inline locale map ({ en, "zh-CN" }) resolved at render time icon stringoptional Page icon name type Enum<'record' | 'home' | 'app' | 'utility' | 'list'>optional Page type variables { name: string; type?: Enum<'string' | 'number' | 'boolean' | 'object' | 'array' | 'record_id'>; defaultValue?: any; source?: string }[]optional Local page state, exposed to expressions as page.<name> and writable by interactive elements via source (master/detail, filtered dashboards). object stringoptional Bound object (for Record pages) template stringoptional Layout template name (e.g. "header-sidebar-main") regions { name: string; width?: Enum<'small' | 'medium' | 'large' | 'full'>; components: object[] }[]optional Layout regions (header, main, sidebar, footer) with their components. Optional — list pages use interfaceConfig, slotted pages use slots, and an empty full page falls back to the synthesized default layout. isDefault booleanoptional assignedProfiles string[]optional interfaceConfig { source?: string; columns?: string[] | object[]; sort?: object[]; filterBy?: object[]; … }optional Interface-level page configuration (for Airtable-style interface pages) aria { ariaLabel?: string | Record<string, string>; ariaDescribedBy?: string; role?: string }optional ARIA accessibility attributes kind Enum<'full' | 'slotted' | 'html' | 'react' | 'jsx'>optional Page override mode. full | slotted = structured authoring; html = author-written constrained JSX/HTML+Tailwind compiled (parsed, never executed) to the tree (ADR-0080; the legacy value 'jsx' is a deprecated alias); react = real-React source executed at render by the runtime (ADR-0081); it runs author JS, so it is gated by a host capability that defaults ON and is disabled server-side via the OS_PAGE_REACT=off env toggle. slots { header?: object | object[]; actions?: object | object[]; alerts?: object | object[]; highlights?: object | object[]; … }optional Slot override map for slotted pages source stringoptional Page source text. For kind==='html' (alias 'jsx') it is constrained JSX/HTML+Tailwind compiled to the tree by @objectstack/sdui-parser at save time (parse, never execute). For kind==='react' it is real React/JSX executed at render by @object-ui/react-runtime (trusted tier). Authoritative over regions in both. requires string[]optional Plugin namespaces the JSX source references (validated at save and load) _lock Enum<'none' | 'no-overlay' | 'no-delete' | 'full'>optional Item-level lock — controls overlay & delete (ADR-0010). _lockReason stringoptional Human-readable reason shown when a write is refused by _lock. _lockSource Enum<'artifact' | 'package' | 'env-forced'>optional Layer that set _lock (artifact | package | env-forced). _provenance Enum<'package' | 'org' | 'env-forced'>optional Origin of the item (package | org | env-forced). _packageId stringoptional Owning package machine id. _packageVersion stringoptional Owning package version. _lockDocsUrl stringoptional Optional documentation link surfaced next to _lockReason.
Property Type Required Description type Enum<'page:header' | 'page:footer' | 'page:sidebar' | 'page:tabs' | 'page:accordion' | 'page:card' | 'page:section' | 'record:details' | 'record:highlights' | 'record:related_list' | 'record:activity' | 'record:chatter' | 'record:path' | 'record:alert' | 'record:quick_actions' | 'record:reference_rail' | 'record:history' | 'app:launcher' | 'nav:menu' | 'nav:breadcrumb' | 'global:search' | 'global:notifications' | 'user:profile' | 'ai:chat_window' | 'ai:suggestion' | 'element:text' | 'element:number' | 'element:image' | 'element:divider' | 'element:button' | 'element:filter' | 'element:form' | 'element:record_picker' | 'element:text_input'> | string✅ Component Type (Standard enum or custom string) id stringoptional Unique instance ID label string | Record<string, string>optional Display label — the default-language string, or an inline locale map ({ en, "zh-CN" }) resolved at render time properties Record<string, any>optional Component props passed to the widget. See component.zod.ts for schemas. events Record<string, string>optional Event handlers map style Record<string, string>optional Inline styles or utility classes className stringoptional CSS class names responsiveStyles { large?: Record<string, string | number>; medium?: Record<string, string | number>; small?: Record<string, string | number>; xsmall?: Record<string, string | number> }optional Per-breakpoint scoped style maps (ADR-0065) visibleWhen string | { dialect: Enum<'cel' | 'cron' | 'template'>; source?: string; ast?: any; meta?: object }optional Visibility predicate (CEL) — component rendered only when TRUE. Binds record, current_user, page.<var>. e.g. "page.selectedProjectId != ''" visibility string | { dialect: Enum<'cel' | 'cron' | 'template'>; source?: string; ast?: any; meta?: object }optional [DEPRECATED → visibleWhen] Visibility predicate (CEL). Normalized to visibleWhen at parse. dataSource { object: string; view?: string; filter?: any; sort?: object[]; … }optional Per-element data binding for multi-object pages responsive { breakpoint?: Enum<'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'>; hiddenOn?: Enum<'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'>[]; columns?: object; order?: object }optional Responsive layout configuration aria { ariaLabel?: string | Record<string, string>; ariaDescribedBy?: string; role?: string }optional ARIA accessibility attributes
page:header
page:footer
page:sidebar
page:tabs
page:accordion
page:card
page:section
record:details
record:highlights
record:related_list
record:activity
record:chatter
record:path
record:alert
record:quick_actions
record:reference_rail
record:history
app:launcher
nav:menu
nav:breadcrumb
global:search
global:notifications
user:profile
ai:chat_window
ai:suggestion
element:text
element:number
element:image
element:divider
element:button
element:filter
element:form
element:record_picker
element:text_input
Property Type Required Description name string✅ Region name (e.g. "sidebar", "main", "header") width Enum<'small' | 'medium' | 'large' | 'full'>optional components { type: Enum<'page:header' | 'page:footer' | 'page:sidebar' | 'page:tabs' | 'page:accordion' | … +29 more> | string; id?: string; label?: string | Record<string, string>; properties?: Record<string, any>; … }[]✅ Components in this region
Page type — the page KIND. Only types with a dedicated renderer are authorizable; visualizations of a list page live in interfaceConfig, not here.
record
home
app
utility
list
Property Type Required Description name string✅ Variable name. Exposed to expressions as page.<name>. type Enum<'string' | 'number' | 'boolean' | 'object' | 'array' | 'record_id'>✅ defaultValue anyoptional Initial value. Defaults to a type-appropriate empty value when omitted. source stringoptional Component id that writes this variable (e.g. an element:record_picker whose id matches).