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
TypeScript Usage
import { ElementDataSource, InterfacePageConfig, Page, PageComponent, PageComponentType, PageRegion, PageType, PageVariable } from '@objectstack/spec/ui';
import type { ElementDataSource, InterfacePageConfig, Page, PageComponent, PageComponentType, PageRegion, PageType, PageVariable } from '@objectstack/spec/ui';
// Validate data
const result = ElementDataSource.parse(data);ElementDataSource
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| object | string | ✅ | Object to query |
| view | string | optional | Named view to apply |
| filter | [__schema0](./__schema0) | optional | Additional filter criteria |
| sort | Object[] | optional | Sort order |
| limit | integer | optional | Max records to display |
InterfacePageConfig
Interface-level page configuration (Airtable parity)
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| source | string | optional | Source object name for the page |
| columns | string[] | Object[] | optional | Columns shown by the page. Blank = all object fields. Defined directly on the page (no view inheritance). |
| sort | Object[] | optional | Default sort order for the page, defined directly on the page. |
| filterBy | Object[] | optional | Always-on page filter (base filter). |
| levels | integer | optional | Number of hierarchy levels to display |
| sourceView | string | optional | @deprecated Legacy named-view inheritance. Define columns/sort/filterBy on the page instead. |
| appearance | Object | optional | Appearance and visualization configuration |
| userFilters | Object | optional | End-user quick-filter bar for this page (overrides the source view's userFilters) |
| userActions | Object | optional | User action toggles |
| addRecord | Object | 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 | boolean | optional | Show record count at page bottom |
| allowPrinting | boolean | optional | Allow users to print the page |
Page
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| name | string | ✅ | Page unique name (lowercase snake_case) |
| label | string | ✅ | Display label (plain string; i18n keys are auto-generated by the framework) |
| description | string | optional | Display label (plain string; i18n keys are auto-generated by the framework) |
| icon | string | optional | Page icon name |
| type | Enum<'record' | 'home' | 'app' | 'utility' | 'list'> | optional | Page type |
| variables | Object[] | optional | Local page state, exposed to expressions as page.<name> and writable by interactive elements via source (master/detail, filtered dashboards). |
| object | string | optional | Bound object (for Record pages) |
| template | string | optional | Layout template name (e.g. "header-sidebar-main") |
| regions | 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 | boolean | optional | |
| assignedProfiles | string[] | optional | |
| interfaceConfig | Object | optional | Interface-level page configuration (for Airtable-style interface pages) |
| aria | Object | 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 | Object | optional | Slot override map for slotted pages |
| source | string | optional | 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) |
PageComponent
Properties
| 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 | string | optional | Unique instance ID |
| label | string | optional | Display label (plain string; i18n keys are auto-generated by the framework) |
| 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 | string | optional | CSS class names |
| responsiveStyles | Object | optional | Per-breakpoint scoped style maps (ADR-0065) |
| visibleWhen | string | Object | optional | Visibility predicate (CEL) — component rendered only when TRUE. Binds record, current_user, page.<var>. e.g. "page.selectedProjectId != ''" |
| visibility | string | Object | optional | [DEPRECATED → visibleWhen] Visibility predicate (CEL). Normalized to visibleWhen at parse. |
| dataSource | Object | optional | Per-element data binding for multi-object pages |
| responsive | Object | optional | Responsive layout configuration |
| aria | Object | optional | ARIA accessibility attributes |
PageComponentType
Allowed Values
page:headerpage:footerpage:sidebarpage:tabspage:accordionpage:cardpage:sectionrecord:detailsrecord:highlightsrecord:related_listrecord:activityrecord:chatterrecord:pathrecord:alertrecord:quick_actionsrecord:reference_railrecord:historyapp:launchernav:menunav:breadcrumbglobal:searchglobal:notificationsuser:profileai:chat_windowai:suggestionelement:textelement:numberelement:imageelement:dividerelement:buttonelement:filterelement:formelement:record_pickerelement:text_input
PageRegion
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| name | string | ✅ | Region name (e.g. "sidebar", "main", "header") |
| width | Enum<'small' | 'medium' | 'large' | 'full'> | optional | |
| components | Object[] | ✅ | Components in this region |
PageType
Page type — the page KIND. Only types with a dedicated renderer are authorizable; visualizations of a list page live in interfaceConfig, not here.
Allowed Values
recordhomeapputilitylist
PageVariable
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| name | string | ✅ | Variable name. Exposed to expressions as page.<name>. |
| type | Enum<'string' | 'number' | 'boolean' | 'object' | 'array' | 'record_id'> | ✅ | |
| defaultValue | any | optional | Initial value. Defaults to a type-appropriate empty value when omitted. |
| source | string | optional | Component id that writes this variable (e.g. an element:record_picker whose id matches). |