ObjectUIObjectUI

Schema Type Reference

Complete API reference for all ObjectUI schema types with annotated examples

Schema Type Reference

This reference documents every ObjectUI schema type with annotated JSON examples. Each schema extends BaseSchema and can be rendered by the ObjectUI engine from pure JSON.

Import: All types are available from @object-ui/types.

import type { PageNodeSchema, FormSchema, TableSchema, /* ... */ } from '@object-ui/types';

Base Schema

SchemaNode

The foundational building block of ObjectUI. Every component in the system is described by a SchemaNode. It can be a full schema object, or a primitive value rendered as text.

import type { BaseSchema } from '@object-ui/types';

// The definition `@object-ui/types` declares
type SchemaNode = BaseSchema | string | number | boolean | null | undefined;

BaseSchema

All schema types extend BaseSchema. These shared properties are available on every component.

{
  "type": "div",
  "id": "my-component",
  "name": "wrapper",
  "label": "Wrapper",
  "description": "A container element",
  "className": "p-4 bg-white rounded-lg",
  "visible": true,
  "visibleOn": "${data.showWrapper}",
  "disabled": false,
  "disabledOn": "${data.isLocked}",
  "testId": "wrapper-element",
  "ariaLabel": "Content wrapper",
  "body": []
}

One row per declared member, in declaration order, so the list can be checked against BaseSchema by reading the two side by side.

PropertyTypeDescription
typestringRequired. Component type identifier (e.g. "page", "form", "table").
idstringUnique instance identifier.
namestringComponent name, used for form fields and data binding.
labelstring | I18nLabelHuman-readable display label. I18nLabel is the spec's inline locale map (string | Record<string, string>, keyed by BCP-47 locale tag such as en or zh-CN), resolved against the display locale by resolveI18nLabel.
descriptionstring | I18nLabelHelp text or tooltip content. Same inline-locale-map vocabulary and resolver as label.
placeholderstringHint text for input components.
classNamestringTailwind CSS utility classes.
styleRecord<string, string | number>Inline CSS styles. Use sparingly — prefer className.
dataanyArbitrary data attached to the node. any because the shape is defined by the consuming component rather than by BaseSchema.
bindstringData-scope path this node draws its rows or value from, resolved by useDataScope(). Honoured only by components that call it.
bodySchemaNode | SchemaNode[]Child components rendered inside this component.
childrenSchemaNode | SchemaNode[]Alias for body.
visibleboolean | string | { dialect?: string; source: string }Visibility control. Accepts a boolean, a predicate expression string, or the CEL envelope object ({ dialect: 'cel', source } — what objectstack build emits for every authored predicate) — the renderer evaluates this key rather than reading it as a boolean. The string-or-envelope half is ExpressionWire, the one wire type visibleWhen on form fields already carries.
visibleWhenstringCanonical conditional-visibility predicate (ADR-0089); the element is shown when it evaluates truthy. Evaluated before visible and visibleOn, and outranks both.
visibleOnstringExpression for conditional visibility. Deprecated (ADR-0089) — use visibleWhen.
hiddenboolean | string | { dialect?: string; source: string }Inverse of visible — the node is not rendered. Accepts a boolean, a predicate expression string or the CEL envelope object (ExpressionWire), which the renderer evaluates rather than reading as a boolean; hiddenOn remains the sibling spelling.
hiddenOnstringExpression for conditional hiding.
disabledboolean | string | { dialect?: string; source: string }Disabled state. Accepts a boolean, a predicate expression string or the CEL envelope object (ExpressionWire), on the same evaluated path as visible.
disabledOnstringExpression for conditional disabling.
testIdstringTest identifier, rendered as data-testid.
ariaLabelstring | KeyedI18nLabelAccessibility label, rendered as aria-label. KeyedI18nLabel is the keyed form ({ key, defaultValue?, params? }), resolved by resolveKeyedI18nLabelnot the I18nLabel that label and description carry. The two are structurally confusable and each returns nothing useful for the other's input.

Two things the table cannot show in a cell:

  • A concrete schema may narrow an inherited member, and its own declaration wins. Many component schemas restate label, description or disabled more narrowly than BaseSchema declares them, so the unions above are what a node gets when its own schema does not restate the key. Check the component's own property table before writing a predicate string or a locale map into an inherited slot.
  • This list is exhaustive for declared members, not for accepted keys. BaseSchema carries an index signature ([key: string]: any) and its Zod mirror is .passthrough(), so an undeclared key — a misspelling included — is still accepted by both halves. Absence from this table does not mean a key is rejected.

Layout Schemas

PageNodeSchema

Top-level page container. Defines a full page with optional regions (header, sidebar, footer).

{
  "type": "page",
  "title": "User Dashboard",
  "icon": "LayoutDashboard",
  "description": "Overview of user activity",
  "pageType": "detail",
  "object": "User",
  "variables": [
    { "name": "userId", "type": "string", "defaultValue": "current" }
  ],
  "regions": [
    {
      "name": "header",
      "body": [{ "type": "text", "body": "Welcome back" }]
    }
  ],
  "body": [
    { "type": "card", "title": "Activity", "body": [] }
  ]
}
PropertyTypeDescription
titlestringPage title displayed in the header.
iconstringLucide icon name for the page.
pageTypePageTypePage purpose: "list", "detail", "form", "dashboard", "report", "custom".
objectstringObjectQL object name this page operates on.
templatestringTemplate name for page layout.
variablesPageVariable[]Page-level variables with types and defaults.
regionsPageRegion[]Named layout regions (header, sidebar, footer).
bodySchemaNode[]Main page content.
isDefaultbooleanWhether this is the default page for the object.
assignedProfilesstring[]Security profiles that can access this page.

Related: AppSchema, DivSchema, GridSchema


DivSchema

A generic container element. The simplest layout primitive.

{
  "type": "div",
  "className": "flex items-center gap-4 p-6",
  "children": [
    { "type": "text", "body": "Hello World" },
    { "type": "button", "label": "Click me" }
  ]
}
PropertyTypeDescription
childrenSchemaNode | SchemaNode[]Child elements to render inside the div.

Related: GridSchema, CardSchema


CardSchema

A styled container with optional header, body, and footer regions.

{
  "type": "card",
  "title": "Revenue Summary",
  "description": "Monthly revenue breakdown",
  "variant": "outline",
  "hoverable": true,
  "header": [
    { "type": "badge", "label": "Live", "variant": "success" }
  ],
  "body": [
    { "type": "statistic", "label": "Total Revenue", "value": "$12,400" }
  ],
  "footer": [
    { "type": "button", "label": "View Details", "variant": "ghost" }
  ]
}
PropertyTypeDescription
titlestringCard title text.
descriptionstringSubtitle / description text.
variant"default" | "outline" | "ghost"Visual style variant.
hoverablebooleanAdd hover elevation effect.
clickablebooleanMake the entire card a click target.
headerSchemaNode | SchemaNode[]Content rendered in the card header.
bodySchemaNode | SchemaNode[]Main card content.
footerSchemaNode | SchemaNode[]Content rendered in the card footer.

Related: DivSchema, GridSchema


GridSchema

A responsive grid layout. Columns can be a fixed number or responsive breakpoints.

{
  "type": "grid",
  "columns": { "sm": 1, "md": 2, "lg": 3 },
  "gap": 6,
  "children": [
    { "type": "card", "title": "Card 1", "body": [] },
    { "type": "card", "title": "Card 2", "body": [] },
    { "type": "card", "title": "Card 3", "body": [] }
  ]
}
PropertyTypeDescription
columnsnumber | Record<string, number>Number of columns, or responsive map (e.g. { sm: 1, md: 2, lg: 3 }).
gapnumberGap between grid items (Tailwind spacing scale).
childrenSchemaNode | SchemaNode[]Grid items.

Related: DivSchema, CardSchema, DashboardComponentSchema


TabsSchema

A tabbed interface for organizing content into switchable panels.

{
  "type": "tabs",
  "defaultValue": "overview",
  "orientation": "horizontal",
  "items": [
    {
      "value": "overview",
      "label": "Overview",
      "icon": "Info",
      "content": { "type": "div", "body": [{ "type": "text", "body": "Overview content" }] }
    },
    {
      "value": "settings",
      "label": "Settings",
      "icon": "Settings",
      "content": { "type": "form", "fields": [] }
    }
  ]
}
PropertyTypeDescription
defaultValuestringInitially active tab value.
valuestringControlled active tab value.
orientation"horizontal" | "vertical"Tab bar orientation.
itemsTabItem[]Tab definitions, each with value, label, icon, content, and optional disabled.

Related: CardSchema, PageNodeSchema


Form Schemas

FormSchema

A complete form with fields, validation, layout, and actions.

{
  "type": "form",
  "layout": "horizontal",
  "columns": 2,
  "validationMode": "onBlur",
  "submitLabel": "Save Changes",
  "showCancel": true,
  "cancelLabel": "Discard",
  "defaultValues": {
    "name": "",
    "email": "",
    "role": "viewer"
  },
  "fields": [
    { "name": "name", "label": "Full Name", "type": "text", "required": true },
    { "name": "email", "label": "Email", "type": "email", "required": true },
    { "name": "role", "label": "Role", "type": "select", "options": [
      { "label": "Admin", "value": "admin" },
      { "label": "Editor", "value": "editor" },
      { "label": "Viewer", "value": "viewer" }
    ]}
  ]
}
PropertyTypeDescription
fieldsFormField[]Field definitions for the form.
defaultValuesRecord<string, any>Initial form values.
layout"vertical" | "horizontal"Field label placement.
columnsnumberNumber of columns for field layout.
validationMode"onSubmit" | "onBlur" | "onChange" | "onTouched" | "all"When validation triggers.
submitLabelstringText for the submit button.
cancelLabelstringText for the cancel button.
showCancelbooleanWhether to show a cancel button.
showActionsbooleanWhether to show the action buttons row.
resetOnSubmitbooleanReset form after successful submit.
mode"edit" | "read" | "disabled"Form interaction mode.
actionsSchemaNode[]Custom action buttons to replace defaults.

Related: InputSchema, SelectSchema, ObjectFormSchema


InputSchema

A text input field supporting multiple input types with validation.

{
  "type": "input",
  "name": "email",
  "label": "Email Address",
  "inputType": "email",
  "placeholder": "you@example.com",
  "required": true,
  "description": "We'll never share your email",
  "maxLength": 255
}
PropertyTypeDescription
namestringField name for form data binding.
inputTypestringHTML input type: "text", "email", "password", "number", "tel", "url", "search", "date", "time", "datetime-local".
placeholderstringPlaceholder text.
requiredbooleanWhether the field is required.
readOnlybooleanRender as read-only.
errorstringError message to display.
min / maxnumberNumeric range constraints.
stepnumberStep increment for number inputs.
maxLengthnumberMaximum character length.
patternstringRegex pattern for validation.

Related: FormSchema, SelectSchema


SelectSchema

A dropdown select field with predefined options.

{
  "type": "select",
  "name": "priority",
  "label": "Priority",
  "placeholder": "Choose priority...",
  "required": true,
  "options": [
    { "label": "🔴 Critical", "value": "critical" },
    { "label": "🟠 High", "value": "high" },
    { "label": "🟡 Medium", "value": "medium" },
    { "label": "🟢 Low", "value": "low" }
  ],
  "defaultValue": "medium"
}
PropertyTypeDescription
namestringField name for form data binding.
optionsSelectOption[]Array of { label, value } objects.
placeholderstringPlaceholder text when no value selected.
requiredbooleanWhether selection is required.
defaultValuestringInitial selected value.
errorstringError message to display.

Related: FormSchema, InputSchema


ButtonSchema

An interactive button with variants, icons, and loading states.

{
  "type": "button",
  "label": "Deploy to Production",
  "variant": "default",
  "size": "lg",
  "icon": "Rocket",
  "iconPosition": "left",
  "loading": false,
  "buttonType": "submit"
}
PropertyTypeDescription
labelstringButton text.
variant"default" | "secondary" | "destructive" | "outline" | "ghost" | "link"Visual style.
size"default" | "sm" | "lg" | "icon"Button size.
iconstringLucide icon name.
iconPosition"left" | "right"Icon placement relative to label.
loadingbooleanShow loading spinner and disable interaction.
buttonType"button" | "submit" | "reset"HTML button type.

Related: ActionSchema, FormSchema


Data Display Schemas

TableSchema

A simple static table: it renders inline data against columns, nothing more. For row hover highlighting, striping, sorting, filtering, selection or inline editing use the interactive data-table — the static table deliberately does not implement those (objectui#5474 retired the keys that once suggested it did; authoring them is now refused by validation instead of silently ignored).

{
  "type": "table",
  "caption": "Recent Orders",
  "columns": [
    { "accessorKey": "id", "header": "#", "width": 60 },
    { "accessorKey": "customer", "header": "Customer" },
    { "accessorKey": "amount", "header": "Amount", "cellClassName": "text-right" },
    { "accessorKey": "status", "header": "Status" }
  ],
  "data": [
    { "id": 1, "customer": "Acme Corp", "amount": "$1,200", "status": "Paid" },
    { "id": 2, "customer": "Globex Inc", "amount": "$3,400", "status": "Pending" }
  ],
  "footer": { "type": "text", "body": "Showing 2 of 156 orders" }
}
PropertyTypeDescription
captionstringTable caption / title text.
columnsStaticTableColumn[]Column definitions — the static subset: accessorKey (the row key to read) and header (heading text) are required; width, className, and cellClassName are the only other keys this renderer honours. Interactive column keys (align, sortable, filterable, resizable, editable, cell, fixed, minWidth, type) belong to data-table's rich TableColumn and are refused here.
dataany[]Array of row data objects.
footerSchemaNode | stringFooter content below the table.

Related: ObjectGridSchema


ChartSchema

A chart visualization supporting multiple chart types.

{
  "type": "chart",
  "chartType": "bar",
  "title": "Monthly Revenue",
  "description": "Revenue by month for 2024",
  "height": 350,
  "showLegend": true,
  "showGrid": true,
  "animate": true,
  "xAxisKey": "month",
  "data": [
    { "month": "Jan", "Revenue": 4200, "Expenses": 3100 },
    { "month": "Feb", "Revenue": 5100, "Expenses": 3400 },
    { "month": "Mar", "Revenue": 4800, "Expenses": 3200 },
    { "month": "Apr", "Revenue": 6200, "Expenses": 3800 },
    { "month": "May", "Revenue": 5800, "Expenses": 3600 },
    { "month": "Jun", "Revenue": 7100, "Expenses": 4000 }
  ],
  "series": [
    {
      "name": "Revenue",
      "color": "#3b82f6"
    },
    {
      "name": "Expenses",
      "color": "#ef4444"
    }
  ]
}

The rows live on the chart node's own data, one object per row keyed by column name. Each series' name (or dataKey) selects the column it plots within those rows, and xAxisKey names the column on the category axis. A series carries no numbers of its own: ChartDataSeries.data is a retirement tombstone (objectui#6896) and an authored array is refused by name at parse.

PropertyTypeDescription
chartTypeChartTypeRequired. "bar", "line", "area", "pie", "donut", "radar", "scatter", "heatmap".
titlestringChart title.
descriptionstringChart description / subtitle.
categoriesstring[]An alternative series list — column names to plot, read only when series is absent, and ignored outright when it is present. Not axis labels: the category axis comes from xAxisKey.
seriesChartDataSeries[]Data series. Each entry's name (or dataKey) names the column it plots within a data row; optional label, color, a per-series type ("bar", "line", "area") for combo charts, stack, yAxis ("left" / "right"), variant ("primary" / "comparison"), dashArray and opacity. chartType on a series is refused by name — it is the renderer's internal spelling of type; write type.
dataArray<Record<string, any>>Rows to plot — one object per row, keyed by column name.
xAxisKeystringRow key holding the category (x) axis. The bare-string xAxis: "month" spelling folds onto this key at parse.
height / widthstring | numberChart dimensions.
showLegendbooleanDisplay the legend.
showGridbooleanDisplay grid lines.
animatebooleanEnable entry animations.
configRecord<string, any>Additional chart library configuration.

Related: DashboardComponentSchema, CardSchema


TreeViewSchema

A hierarchical tree component for nested data with expand/collapse and selection.

{
  "type": "tree-view",
  "multiSelect": false,
  "showLines": true,
  "defaultExpandedIds": ["root", "src"],
  "nodes": [
    {
      "id": "root",
      "label": "project",
      "icon": "Folder",
      "children": [
        {
          "id": "src",
          "label": "src",
          "icon": "Folder",
          "children": [
            { "id": "app", "label": "App.tsx", "icon": "FileCode" },
            { "id": "index", "label": "index.ts", "icon": "FileCode" }
          ]
        },
        { "id": "readme", "label": "README.md", "icon": "FileText" }
      ]
    }
  ]
}
PropertyTypeDescription
nodesTreeNode[]Optional. Nested tree data — the spelling the renderer reads FIRST, and the one the component's own inputs and defaultProps use. Each node has id, label, optional icon and children.
dataTreeNode[]Optional. Nested tree data, read only when nodes is absent (the renderer reads nodes first — objectui#6939).
defaultExpandedIdsstring[]Node IDs expanded on initial render.
defaultSelectedIdsstring[]Node IDs selected on initial render.
expandedIdsstring[]Controlled expanded state.
selectedIdsstring[]Controlled selection state.
multiSelectbooleanAllow selecting multiple nodes.
showLinesbooleanShow tree connector lines.

Related: TableSchema


CRUD Schemas

CRUDSchema — retired

CRUDSchema and the crud node type were removed in objectui#5373 under ADR-0049 (enforce-or-remove). The type had four declaration faces — a TypeScript interface, a zod mirror, a branch in the schema validator and a CRUDBuilder — and no registered renderer, for the whole life of the key. A node that spelled it painted the OBJUI-001 "Unknown component type" panel, so this page was teaching a shape that could not render.

There is no drop-in replacement, because a CRUD screen is a composition rather than one node. Build it from the shapes that do render:

What CRUDSchema promisedWhat to author instead
The record table, with toolbar, filters, pagination and row/batch actionsObjectGridSchema
The create/edit formObjectFormSchema
The single-record read viewDetailSchema / DetailViewSchema
Whole-object screens that bundle the aboveObjectViewSchema

The defaultSort and defaultSortOrder keys documented here were CRUDSchema's own — a flat field name plus a separate direction. They are gone with it. ObjectGridSchema declares its own, differently shaped defaultSort (an object with field and order); that key is unaffected.

Authoring crud is now refused by name: validateSchema from @object-ui/core returns a RETIRED_TYPE error on schema.type naming the migration above, and objectui check reports the type as unknown.


ActionSchema

A powerful action definition supporting API calls, confirmations, dialogs, chaining, and conditional execution.

{
  "type": "action",
  "label": "Submit Order",
  "level": "primary",
  "icon": "Send",
  "actionType": "ajax",
  "api": "/api/orders",
  "method": "POST",
  "data": { "status": "submitted" },
  "confirmText": "This will send the order to the warehouse.",
  "successMessage": "Order submitted successfully",
  "errorMessage": "Failed to submit order",
  "chain": [
    {
      "type": "action",
      "label": "Refresh",
      "actionType": "button",
      "reload": true
    }
  ],
  "chainMode": "sequential",
  "condition": "${data.items.length > 0}",
  "retry": {
    "maxAttempts": 3,
    "delay": 1000
  }
}
PropertyTypeDescription
labelstringRequired. Action display text.
levelstringSemantic level: "primary", "secondary", "success", "warning", "danger", "info".
iconstringLucide icon name.
actionTypestringAction kind: "button", "link", "dropdown", "ajax", "confirm", "dialog".
apistringAPI endpoint for ajax actions.
methodstringHTTP method: "GET", "POST", "PUT", "DELETE", "PATCH".
dataanyRequest body data.
confirmTextstringConfirmation message shown before executing — the one confirm spelling, addressed by the translation bundle. (A structured confirm object was retired in objectui#4314.)
dialogobjectModal dialog with title, content, size, actions.
chainActionSchema[]Actions to execute after this action completes.
chainMode"sequential" | "parallel"How chained actions execute.
conditionboolean | string | { dialect?, source }Execution gate — the action runs only while this predicate holds (boolean, bare CEL, ${...} template, or the normalized envelope). Declared and false skips the action; absent executes it. It is a gate, not a branch: express a branch as separate actions with mutually exclusive conditions. (The { expression, then, else } branch shape was retired in objectui#3917 — nothing read it, so it ran unconditionally.)
successMessage / errorMessagestringToast messages on success/failure.
reloadbooleanReload data after action completes.
redirectstringURL to navigate to after action.
retryobjectRetry config with maxAttempts and delay.

Related: DetailSchema, ButtonSchema


DetailSchema

A single-record detail view with grouped fields, actions, and tabs.

{
  "type": "detail",
  "title": "Order #1042",
  "api": "/api/orders/1042",
  "showBack": true,
  "groups": [
    {
      "title": "Customer Info",
      "fields": [
        { "name": "customer", "label": "Customer", "type": "text" },
        { "name": "email", "label": "Email", "type": "email" },
        { "name": "created", "label": "Created", "type": "date", "format": "MMM d, yyyy" }
      ]
    },
    {
      "title": "Order Details",
      "fields": [
        { "name": "total", "label": "Total", "type": "text" },
        { "name": "status", "label": "Status", "type": "badge" }
      ]
    }
  ],
  "actions": [
    { "type": "action", "label": "Edit", "icon": "Pencil", "level": "primary" },
    { "type": "action", "label": "Delete", "icon": "Trash2", "level": "danger", "actionType": "confirm" }
  ],
  "tabs": [
    {
      "key": "items",
      "label": "Line Items",
      "content": { "type": "table", "columns": [], "data": [] }
    },
    {
      "key": "history",
      "label": "History",
      "content": { "type": "timeline", "events": [] }
    }
  ]
}
PropertyTypeDescription
titlestringDetail page title.
apistringAPI endpoint to fetch record data.
resourceIdstring | numberID of the record to display.
groupsarrayField groups, each with title, description, and fields.
actionsActionSchema[]Available actions (edit, delete, etc.).
tabsarrayAdditional tabbed content with key, label, and content.
showBackbooleanShow a back navigation button.
loadingbooleanShow loading state.

Related: DetailViewSchema, ObjectGridSchema


ObjectQL Schemas

These schemas integrate with ObjectStack for automatic data fetching, but work with any backend through the data prop.

ObjectGridSchema

A data grid that auto-fetches from an ObjectQL object definition. Includes search, filters, pagination, grouping, and inline editing.

{
  "type": "object-grid",
  "objectName": "Contact",
  "title": "All Contacts",
  "description": "Manage your contacts",
  "showSearch": true,
  "showFilters": true,
  "showPagination": true,
  "pageSize": 25,
  "resizableColumns": true,
  "striped": true,
  "columns": [
    { "field": "name" },
    { "field": "email" },
    { "field": "company" },
    { "field": "phone" },
    { "field": "status", "label": "Status", "sortable": true }
  ],
  "defaultSort": { "field": "name", "order": "asc" },
  "operations": {
    "create": true,
    "read": true,
    "update": true,
    "delete": true,
    "export": true
  },
  "rowActions": ["edit", "delete"],
  "selection": {
    "enabled": true,
    "mode": "multiple"
  },
  "pagination": {
    "enabled": true,
    "pageSize": 25,
    "pageSizeOptions": [10, 25, 50, 100]
  }
}
PropertyTypeDescription
objectNamestringRequired. ObjectQL object API name.
columnsstring[] | ListColumn[]Columns to display. Either a plain array of field names (["name", "email"]), which auto-resolve from object metadata, or an array of ListColumn objects whose identity key is field ({ "field": "status", "label": "Status" }) — never name. Do not mix the two forms in one array: the array is dispatched on its first entry, so column objects sitting behind a bare string are dropped.
filterany[]Pre-applied filter conditions.
sortstring | SortConfig[]Default sort configuration.
searchableFieldsstring[]Fields included in search.
selectionSelectionConfigRow selection configuration.
paginationPaginationConfigPagination settings.
operationsobjectEnabled CRUD operations.
rowActions / bulkActionsstring[]Action identifiers for rows and batch selection. bulkActions is the spec-aligned key; batchActions is a legacy alias that takes precedence when both are set.
editablebooleanEnable inline cell editing.
groupingGroupingConfigRow grouping configuration. Page-scoped: the grid groups the rows it has fetched, so group counts are page slices and a group beyond the page is absent — the grid marks the grouping partial when it can tell.
frozenColumnsnumberNumber of columns frozen on scroll.
navigationViewNavigationConfigSPA navigation configuration.

Related: ObjectViewSchema, TableSchema


ObjectFormSchema

A smart form that auto-generates fields from an ObjectQL object. Supports simple, tabbed, wizard, split, drawer, and modal layouts.

{
  "type": "object-form",
  "objectName": "Contact",
  "mode": "create",
  "formType": "tabbed",
  "title": "New Contact",
  "layout": "vertical",
  "columns": 2,
  "fields": ["firstName", "lastName", "email", "phone", "company"],
  "sections": [
    {
      "label": "Basic Info",
      "fields": ["firstName", "lastName", "email"]
    },
    {
      "label": "Details",
      "fields": ["phone", "company", "address"]
    }
  ],
  "showSubmit": true,
  "submitText": "Create Contact",
  "showCancel": true,
  "cancelText": "Cancel"
}
PropertyTypeDescription
objectNamestringRequired. ObjectQL object API name.
mode"create" | "edit" | "view"Required. Form interaction mode.
formTypestringLayout type: "simple", "tabbed", "wizard", "split", "drawer", "modal". Aligned with @objectstack/spec FormViewSchema.type.
recordIdstring | numberRecord ID for edit/view modes.
fieldsstring[]Field API names to include (auto-resolved from object metadata).
customFieldsFormField[]Manually defined fields that override auto-generated ones.
sectionsObjectFormSection[]Field sections (simple groups, tabs, or wizard steps depending on formType). Spec-aligned key.
groupsarrayDeprecated. Legacy alias of sections (spec defines groups as an alias); normalized into sections when sections is absent. Legacy shape: titlelabel, defaultCollapsedcollapsed.
layoutstringLabel layout: "vertical", "horizontal", "inline", "grid".
columnsnumberNumber of form columns.
submitText / cancelTextstringButton labels.
showSubmit / showCancel / showResetbooleanToggle action buttons.
drawerSidestringDrawer position: "top", "bottom", "left", "right".
modalSizestringModal size: "sm", "default", "lg", "xl", "full".

Spec alignment & extension keys

ObjectFormSchema keys fall into three classes (#2545):

  • Spec-aligned — same name and semantics as @objectstack/spec FormViewSchema: title, description, layout, columns, sections, defaultTab, tabPosition, allowSkip, showStepIndicator, splitDirection/splitSize/splitResizable, drawerSide/drawerWidth, modalSize, subforms, submitBehavior (plus formType ↔ spec type).
  • ObjectUI extensions — serializable extras with no spec backing yet: showSubmit/submitText, showCancel/cancelText, showReset, nextText/prevText, successMessage, navigateOnSuccess, resetOnSuccess, modalCloseButton, className, initialValues, fields, customFields. Sanctioned and documented here; candidates for upstreaming into the spec are tracked in #2545.
  • Runtime-only — non-serializable renderer concerns that never appear in view metadata: mode, recordId, open/onOpenChange, readOnly, and all callbacks (onSuccess, onError, onCancel, onStepChange, submitHandler).

Related: FormSchema, ObjectViewSchema


ObjectViewSchema

A complete object management interface combining grid, form, search, filters, and view switching.

{
  "type": "object-view",
  "objectName": "Deal",
  "title": "Sales Pipeline",
  "description": "Manage your deals",
  "defaultViewType": "kanban",
  "showSearch": true,
  "showFilters": true,
  "showCreate": true,
  "showViewSwitcher": true,
  "operations": {
    "create": true,
    "read": true,
    "update": true,
    "delete": true
  },
  "searchableFields": ["name", "company", "owner"],
  "filterableFields": ["stage", "owner", "value"],
  "listViews": {
    "all": {
      "label": "All Deals",
      "filter": [],
      "sort": [{ "field": "value", "order": "desc" }]
    },
    "my-deals": {
      "label": "My Deals",
      "filter": [["owner", "=", "${currentUser.id}"]],
      "default": true
    }
  },
  "table": {
    "columns": ["name", "stage", "value", "owner", "closeDate"],
    "pageSize": 25
  },
  "form": {
    "formType": "drawer",
    "drawerSide": "right",
    "fields": ["name", "stage", "value", "owner", "closeDate", "notes"]
  }
}
PropertyTypeDescription
objectNamestringRequired. ObjectQL object API name.
titlestringView title.
defaultViewTypestringInitial view: "grid", "kanban", "gallery", "calendar", "timeline", "gantt", "map".
listViewsRecord<string, NamedListView>Named list views with filters and sort.
defaultListViewstringKey of the default list view.
tablePartial<ObjectGridSchema>Grid configuration overrides.
formPartial<ObjectFormSchema>Form configuration overrides.
showSearch / showFilters / showCreatebooleanToggle toolbar features.
showViewSwitcherbooleanShow view type toggle (grid, kanban, etc.).
operationsobjectEnabled CRUD operations.
navigationViewNavigationConfigSPA-aware navigation.

Related: ObjectGridSchema, ObjectFormSchema, ViewSwitcherSchema


Complex Schemas

KanbanSchema

A drag-and-drop Kanban board. The kanban type key validates the shape the registered renderer (@object-ui/plugin-kanban) reads: bind the board to an object with objectName + groupBy (the lanes come from the group field's options), or author it statically with columns, each carrying its cards.

{
  "type": "kanban",
  "objectName": "tasks",
  "groupBy": "status",
  "cardTitle": "title",
  "cardFields": ["assignee", "due_date"],
  "quickAdd": true
}

A static board carries its cards inline:

{
  "type": "kanban",
  "columns": [
    {
      "id": "todo",
      "title": "To Do",
      "cards": [
        {
          "id": "task-1",
          "title": "Design mockups",
          "description": "Create wireframes for new feature",
          "badges": [{ "label": "High", "variant": "destructive" }]
        },
        { "id": "task-2", "title": "Write tests", "description": "Unit tests for auth module" }
      ]
    },
    {
      "id": "in-progress",
      "title": "In Progress",
      "limit": 3,
      "cards": [
        { "id": "task-3", "title": "API integration", "description": "Connect to payment gateway" }
      ]
    },
    {
      "id": "done",
      "title": "Done",
      "cards": []
    }
  ]
}
PropertyTypeDescription
objectNamestringObject to fetch records from.
groupBystringField whose values become the lanes (maps to column ids).
swimlaneFieldstringField for swimlane rows (2D grouping).
cardTitlestringField used as the card title.
cardFieldsstring[]Fields rendered on each card.
dataany[]Inline records, bucketed into lanes by groupBy.
limitnumberFetch window for the board (default 100).
columnsKanbanColumn[]Lanes, each with id, title, cards, and optional limit / className / collapsed. A card has id, title, optional description and badges.
quickAddbooleanShow a Quick Add button at the bottom of each column.
coverImageFieldstringField whose URL renders as the card cover image.
allowCollapsebooleanAllow columns to be collapsed.
conditionalFormattingKanbanConditionalFormattingRule[]Card colouring rules — native { field, operator, value } or spec { condition, style }.
cardTemplatesCardTemplate[]Predefined quick-add templates.
columnWidthsColumnWidthConfigColumn width configuration.
groupingGroupingConfigListView grouping config; its first field is the swimlane fallback.
onCardMovefunctionRuntime slot supplied by a React host, (cardId, fromColumnId, toColumnId, newIndex); not authorable in JSON.
onCardClickfunctionRuntime slot supplied by a React host, (card, event?); not authorable in JSON. On the object-bound board the host's handler runs alongside the record-detail overlay.
onQuickAddfunctionRuntime slot supplied by a React host, (columnId, title); not authorable in JSON.

The former @object-ui/types kanban dialect — DeclarativeKanbanSchema, with a board-level draggable, a column color and card labels / priority — was retired in objectui#7664: no registered renderer read it, so a board written that way validated and rendered empty. draggable and a column color are now refused by name; a static board written with columns[].cards[] as above is the same document in both dialects and renders every card.

Related: ObjectViewSchema, ObjectGridSchema


DashboardComponentSchema

A widget-based dashboard with configurable grid layout and auto-refresh.

{
  "type": "dashboard",
  "columns": 4,
  "gap": 6,
  "refreshInterval": 30000,
  "widgets": [
    {
      "id": "revenue",
      "title": "Total Revenue",
      "description": "Monthly revenue",
      "colSpan": 1,
      "rowSpan": 1,
      "body": {
        "type": "statistic",
        "label": "Revenue",
        "value": "$48,200",
        "trend": { "value": 12, "direction": "up" }
      }
    },
    {
      "id": "chart",
      "title": "Sales Trend",
      "colSpan": 2,
      "rowSpan": 1,
      "body": {
        "type": "chart",
        "chartType": "area",
        "xAxisKey": "day",
        "data": [
          { "day": "Mon", "Sales": 120 },
          { "day": "Tue", "Sales": 180 },
          { "day": "Wed", "Sales": 150 },
          { "day": "Thu", "Sales": 210 },
          { "day": "Fri", "Sales": 190 }
        ],
        "series": [{ "name": "Sales" }]
      }
    },
    {
      "id": "tasks",
      "title": "Recent Tasks",
      "colSpan": 1,
      "rowSpan": 1,
      "body": {
        "type": "list",
        "items": []
      }
    }
  ]
}
PropertyTypeDescription
columnsnumberNumber of grid columns.
gapnumberGap between widgets (Tailwind spacing scale).
widgetsDashboardWidgetSchema[]Required. Widget definitions with id, title, colSpan, rowSpan, and body.
refreshIntervalnumberAuto-refresh interval in milliseconds.

Each widget supports colSpan and rowSpan to control its size in the grid. The body can be any SchemaNode.

Related: GridSchema, ChartSchema, CardSchema


CalendarViewSchema

A multi-view calendar computed from the node's data records. There is no authorable events key: the renderer builds one event per record in data, reading the fields the field-name properties point at (objectui#5667; an authored events is dropped by design, objectui#4433).

{
  "type": "calendar-view",
  "view": "month",
  "currentDate": "2024-03-15T12:00:00.000Z",
  "data": [
    {
      "id": "evt-1",
      "title": "Team Standup",
      "start": "2024-03-15T09:00:00",
      "end": "2024-03-15T09:30:00",
      "color": "#3b82f6"
    },
    {
      "id": "evt-2",
      "title": "Sprint Review",
      "start": "2024-03-15T14:00:00",
      "end": "2024-03-15T15:00:00",
      "color": "#8b5cf6",
      "allDay": false
    }
  ],
  "allowCreate": true,
  "className": "h-[600px] border rounded-lg"
}
PropertyTypeDescription
dataanyRecords rendered as events — an array, or a binding expression that resolves to one.
titleFieldstringRecord field for the event title. Default "title".
startDateFieldstringRecord field for the event start date/time. Default "start".
endDateFieldstringRecord field for the event end date/time. Default "end".
allDayFieldstringRecord field for the all-day flag. Default "allDay".
colorFieldstringRecord field for the event color. Default "color".
viewCalendarViewModeView mode: "month", "week", "day" — the full union. "agenda" was retired in objectui#5740 and now fails validation. Default "month".
currentDatestring | DateInitial calendar date — an ISO date string when authored as JSON.
allowCreatebooleanShow the "New event" affordance; clicking it dispatches a create action. Default false.
onEventClickfunctionHost-only: forwarded when a React host supplies a function; authored JSON cannot produce one.
onViewChangefunctionHost-only: same rule as onEventClick.

Nine formerly declared keys — events (was required, and dropped by the renderer), defaultView, defaultDate, date, views, editable, onEventCreate, onEventUpdate, onDateChange — were retired in objectui#5667: nothing read them on the authored-node path.

Related: ObjectViewSchema, DashboardComponentSchema


View Schemas

DetailViewSchema

An enhanced detail view for a single record with sections, tabs, related records, and navigation.

{
  "type": "detail-view",
  "title": "Contact Details",
  "objectName": "Contact",
  "resourceId": "contact-123",
  "layout": "grid",
  "columns": 2,
  "showBack": true,
  "backUrl": "/contacts",
  "showEdit": true,
  "editUrl": "/contacts/contact-123/edit",
  "showDelete": true,
  "deleteConfirmation": "Are you sure you want to delete this contact?",
  "sections": [
    {
      "title": "Personal Information",
      "icon": "User",
      "columns": 2,
      "collapsible": true,
      "fields": [
        { "name": "firstName", "label": "First Name", "type": "text" },
        { "name": "lastName", "label": "Last Name", "type": "text" },
        { "name": "email", "label": "Email", "type": "email" },
        { "name": "avatar", "label": "Photo", "type": "image" }
      ]
    }
  ],
  "tabs": [
    {
      "key": "activities",
      "label": "Activities",
      "icon": "Activity",
      "badge": 5,
      "content": { "type": "timeline", "events": [] }
    }
  ],
  "related": [
    {
      "title": "Recent Orders",
      "type": "table",
      "api": "/api/contacts/contact-123/orders",
      "columns": [
        { "name": "id", "label": "Order #" },
        { "name": "total", "label": "Total" },
        { "name": "status", "label": "Status" }
      ]
    }
  ],
  "actions": [
    { "type": "action", "label": "Send Email", "icon": "Mail", "level": "primary" }
  ]
}
PropertyTypeDescription
titlestringDetail page title.
objectNamestringObjectQL object name for data binding.
resourceIdstring | numberRecord ID to display.
apistringAPI endpoint to fetch record data.
dataanyStatic data (if not fetching from API).
layout"vertical" | "horizontal" | "grid"Field layout mode.
columnsnumberGrid columns (for grid layout).
sectionsDetailViewSection[]Field groups with title, icon, fields, collapsible.
fieldsDetailViewField[]Direct fields (without sections).
tabsDetailViewTab[]Tabbed content with key, label, icon, badge, content.
relatedarrayRelated record sections with title, type, api, columns.
actionsActionSchema[]Available actions.
showBack / backUrlboolean / stringBack navigation.
showEdit / editUrlboolean / stringEdit navigation.
showDelete / deleteConfirmationboolean / stringDelete with confirmation message.
header / footerSchemaNodeCustom header/footer content.

Related: DetailSchema, ObjectViewSchema


ViewSwitcherSchema

A toggle control that switches between different view types (list, grid, kanban, calendar, etc.).

{
  "type": "view-switcher",
  "defaultView": "list",
  "variant": "tabs",
  "position": "top",
  "persistPreference": true,
  "storageKey": "contacts-view-pref",
  "views": [
    {
      "type": "list",
      "label": "List View",
      "icon": "List",
      "schema": {
        "type": "object-grid",
        "objectName": "Contact",
        "columns": ["name", "email", "phone"]
      }
    },
    {
      "type": "grid",
      "label": "Card View",
      "icon": "LayoutGrid",
      "schema": {
        "type": "grid",
        "columns": 3,
        "children": []
      }
    },
    {
      "type": "kanban",
      "label": "Kanban",
      "icon": "Kanban",
      "schema": {
        "type": "kanban",
        "columns": []
      }
    }
  ]
}
PropertyTypeDescription
viewsarrayRequired. Available views, each with type, label, icon, and schema.
defaultViewViewTypeInitially active view: "list", "detail", "grid", "kanban", "calendar", "timeline", "map".
activeViewViewTypeControlled active view.
variant"tabs" | "buttons" | "dropdown"Switcher UI style.
position"top" | "bottom" | "left" | "right"Switcher position relative to content.
persistPreferencebooleanSave the user's view preference to storage.
storageKeystringStorage key for persisting the preference.
onViewChangestringExpression or callback invoked on view change.

Related: ObjectViewSchema, KanbanSchema, CalendarViewSchema


Schema Composition

Schemas are designed to compose. Nest any SchemaNode inside another to build complex interfaces:

{
  "type": "page",
  "title": "CRM Dashboard",
  "body": [
    {
      "type": "grid",
      "columns": { "sm": 1, "lg": 2 },
      "gap": 6,
      "children": [
        {
          "type": "card",
          "title": "Quick Stats",
          "body": {
            "type": "dashboard",
            "columns": 2,
            "widgets": [
              { "id": "w1", "title": "Leads", "body": { "type": "statistic", "value": "142" } },
              { "id": "w2", "title": "Revenue", "body": { "type": "statistic", "value": "$24k" } }
            ]
          }
        },
        {
          "type": "card",
          "title": "Recent Activity",
          "body": {
            "type": "tabs",
            "items": [
              { "value": "deals", "label": "Deals", "content": { "type": "table", "columns": [], "data": [] } },
              { "value": "tasks", "label": "Tasks", "content": { "type": "table", "columns": [], "data": [] } }
            ]
          }
        }
      ]
    },
    {
      "type": "object-grid",
      "objectName": "Lead",
      "title": "All Leads",
      "showSearch": true,
      "columns": ["name", "company", "status", "value"]
    }
  ]
}

Type Imports

Import only the types you need:

// Layout
import type { PageNodeSchema, DivSchema, CardSchema, GridSchema, TabsSchema } from '@object-ui/types';

// Forms
import type { FormSchema, InputSchema, SelectSchema, ButtonSchema } from '@object-ui/types';

// Data Display
import type { TableSchema, ChartSchema, TreeViewSchema } from '@object-ui/types';

// CRUD
import type { ActionSchema, DetailSchema } from '@object-ui/types';

// ObjectQL
import type { ObjectGridSchema, ObjectFormSchema, ObjectViewSchema } from '@object-ui/types';

// Complex
import type { KanbanSchema, DashboardComponentSchema, CalendarViewSchema } from '@object-ui/types';

// Views
import type { DetailViewSchema, ViewSwitcherSchema } from '@object-ui/types';

// Base
import type { BaseSchema, SchemaNode } from '@object-ui/types';

Next Steps

On this page