ObjectStackObjectStack

Page Metadata

Build custom pages with component-based layouts, variables, and event handling

Page Metadata

A Page defines a custom UI layout using components, regions, and variables. Unlike Views which are bound to a single Object, Pages are flexible containers that can combine multiple components, embed views, and manage local state.

Basic Structure

const homePage = {
  name: 'sales_home',
  label: 'Sales Home',
  type: 'home',
  regions: [
    {
      name: 'header',
      width: 'full',
      components: [
        {
          type: 'metric_card',
          id: 'total_revenue',
          label: 'Total Revenue',
          properties: {
            object: 'opportunity',
            field: 'amount',
            aggregate: 'sum',
            format: 'currency',
          },
        },
      ],
    },
    {
      name: 'main',
      width: 'large',
      components: [
        {
          type: 'list_view',
          id: 'recent_deals',
          label: 'Recent Deals',
          properties: {
            object: 'opportunity',
            view: 'recent_open',
            limit: 10,
          },
        },
      ],
    },
  ],
};

Page Properties

PropertyTypeRequiredDescription
namestringMachine name (snake_case)
labelstringDisplay label
descriptionstringoptionalPage description
typeenumoptionalPage type (see below; default 'record')
objectstringoptionalAssociated object (for record type)
templatestringoptionalLayout template name (default: 'default')
regionsPageRegion[]optionalLayout regions with components (default []list pages render via interfaceConfig, and an empty record/home/app page falls back to the synthesized default layout)
variablesPageVariable[]optionalLocal state variables
isDefaultbooleanoptionalIs default page for its type
assignedProfilesstring[]optionalProfiles that can access this page

Page Types

TypeDescriptionUse Case
recordTied to a specific object recordCustom detail pages
homeLanding/home pageApp entry points
appGeneral application pageCustom layouts
utilityUtility/helper panelTools, settings, wizards
listRecord list/interface surfaceData-driven interface pages

Earlier roadmap types (dashboard, form, record_detail, record_review, overview, blank) were removed from the schema because they never shipped a renderer (ADR-0049 enforce-or-remove); only the five types above are valid.

Regions

Regions define layout zones on the page. Each region contains components.

regions: [
  {
    name: 'sidebar',
    width: 'small',
    components: [/* ... */],
  },
  {
    name: 'content',
    width: 'large',
    components: [/* ... */],
  },
]
PropertyTypeRequiredDescription
namestringRegion identifier
widthenumoptional'small', 'medium', 'large', 'full'
componentsPageComponent[]Components in this region

Components

Components are the building blocks placed inside regions.

{
  type: 'chart',
  id: 'revenue_chart',
  label: 'Revenue Trend',
  properties: {
    chartType: 'line',
    object: 'opportunity',
    categoryField: 'close_date',
    valueField: 'amount',
  },
  events: {
    onClick: "navigate_to('opportunity_detail', { id: $event.id })",
  },
  visibility: "os.user.profile == 'sales_manager'",
  style: { height: '400px' },
}
PropertyTypeRequiredDescription
typestringComponent type (standard PageComponentType enum or custom string)
idstringoptionalUnique component instance identifier
labelstringoptionalDisplay label
propertiesRecord<string, unknown>optionalComponent-specific configuration (default {} — many components carry no props)
eventsRecord<string, string>optionalEvent handlers (action expressions)
styleobjectoptionalCSS styles
classNamestringoptionalCSS class names
responsiveStylesobjectoptionalPreferred SDUI styling channel (ADR-0065): desktop-first per-breakpoint scoped style maps, compiled to id-scoped CSS at render. Keys are large (the unconditional base), then medium / small / xsmall as max-width overrides. Prefer design tokens, e.g. { large: { padding: 'var(--space-8)' }, small: { padding: 'var(--space-4)' } }. Use over ad-hoc style / className for metadata-authored pages.
visibilitystringoptionalVisibility predicate (CEL expression)

The type field is a union of the standard PageComponentType enum and any custom string. The standard (namespaced) component types include:

  • Structure: page:header, page:footer, page:sidebar, page:tabs, page:accordion, page:card, page:section
  • Record context: record:details, record:highlights, record:related_list, record:activity, record:chatter, record:path, record:alert, record:quick_actions, record:reference_rail, record:history
  • Navigation: app:launcher, nav:menu, nav:breadcrumb
  • Utility: global:search, global:notifications, user:profile
  • AI: ai:chat_window, ai:suggestion
  • Elements: element:text, element:number, element:image, element:divider, element:button, element:filter, element:form, element:record_picker, element:text_input

Components may also carry dataSource (per-element object binding for multi-object pages), responsive, and aria configuration. Custom string types are also accepted for project-specific widgets.

Variables

Pages can define local variables for managing state across components.

variables: [
  {
    name: 'selected_tab',
    type: 'string',
    defaultValue: 'overview',
  },
  {
    name: 'date_range',
    type: 'object',
    defaultValue: { start: null, end: null },
  },
]

Variable type accepts 'string' (default), 'number', 'boolean', 'object', 'array', or 'record_id'.

Complete Example

const accountRecordPage = {
  name: 'account_detail',
  label: 'Account Detail',
  type: 'record',
  object: 'account',
  variables: [
    { name: 'active_tab', type: 'string', defaultValue: 'details' },
  ],
  regions: [
    {
      name: 'header',
      width: 'full',
      components: [
        {
          type: 'record:highlights',
          id: 'header',
          properties: {
            fields: ['name', 'type', 'industry', 'owner'],
            actions: ['edit', 'delete', 'clone'],
          },
        },
      ],
    },
    {
      name: 'sidebar',
      width: 'small',
      components: [
        {
          type: 'record:details',
          id: 'key_fields',
          label: 'Key Fields',
          properties: {
            fields: ['annual_revenue', 'employees', 'website', 'phone'],
          },
        },
        {
          type: 'record:activity',
          id: 'activities',
          label: 'Activity',
        },
      ],
    },
    {
      name: 'main',
      width: 'large',
      components: [
        {
          type: 'record:related_list',
          id: 'contacts',
          label: 'Contacts',
          properties: { object: 'contact', relationship: 'account' },
        },
        {
          type: 'record:related_list',
          id: 'opportunities',
          label: 'Opportunities',
          properties: { object: 'opportunity', relationship: 'account' },
        },
      ],
    },
  ],
};

On this page