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';
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` declarestype SchemaNode = BaseSchema | string | number | boolean | null | undefined;
One row per declared member, in declaration order, so the list can be checked against BaseSchema by reading the two side by side.
Property
Type
Description
type
string
Required. Component type identifier (e.g. "page", "form", "table").
id
string
Unique instance identifier.
name
string
Component name, used for form fields and data binding.
label
string | I18nLabel
Human-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.
description
string | I18nLabel
Help text or tooltip content. Same inline-locale-map vocabulary and resolver as label.
placeholder
string
Hint text for input components.
className
string
Tailwind CSS utility classes.
style
Record<string, string | number>
Inline CSS styles. Use sparingly — prefer className.
data
any
Arbitrary data attached to the node. any because the shape is defined by the consuming component rather than by BaseSchema.
bind
string
Data-scope path this node draws its rows or value from, resolved by useDataScope(). Honoured only by components that call it.
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.
visibleWhen
string
Canonical conditional-visibility predicate (ADR-0089); the element is shown when it evaluates truthy. Evaluated beforevisible and visibleOn, and outranks both.
visibleOn
string
Expression for conditional visibility. Deprecated (ADR-0089) — use visibleWhen.
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.
Disabled state. Accepts a boolean, a predicate expression string or the CEL envelope object (ExpressionWire), on the same evaluated path as visible.
disabledOn
string
Expression for conditional disabling.
testId
string
Test identifier, rendered as data-testid.
ariaLabel
string | KeyedI18nLabel
Accessibility label, rendered as aria-label. KeyedI18nLabel is the keyed form ({ key, defaultValue?, params? }), resolved by resolveKeyedI18nLabel — not 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.
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).
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.
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.
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.
series
ChartDataSeries[]
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.
data
Array<Record<string, any>>
Rows to plot — one object per row, keyed by column name.
xAxisKey
string
Row key holding the category (x) axis. The bare-string xAxis: "month" spelling folds onto this key at parse.
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.
data
TreeNode[]
Optional. Nested tree data, read only when nodes is absent (the renderer reads nodes first — objectui#6939).
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 promised
What to author instead
The record table, with toolbar, filters, pagination and row/batch actions
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.
Confirmation message shown before executing — the one confirm spelling, addressed by the translation bundle. (A structured confirm object was retired in objectui#4314.)
dialog
object
Modal dialog with title, content, size, actions.
chain
ActionSchema[]
Actions to execute after this action completes.
chainMode
"sequential" | "parallel"
How chained actions execute.
condition
boolean | 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.)
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.
filter
any[]
Pre-applied filter conditions.
sort
string | SortConfig[]
Default sort configuration.
searchableFields
string[]
Fields included in search.
selection
SelectionConfig
Row selection configuration.
pagination
PaginationConfig
Pagination settings.
operations
object
Enabled CRUD operations.
rowActions / bulkActions
string[]
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.
editable
boolean
Enable inline cell editing.
grouping
GroupingConfig
Row 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.
Field API names to include (auto-resolved from object metadata).
customFields
FormField[]
Manually defined fields that override auto-generated ones.
sections
ObjectFormSection[]
Field sections (simple groups, tabs, or wizard steps depending on formType). Spec-aligned key.
groups
array
Deprecated. Legacy alias of sections (spec defines groups as an alias); normalized into sections when sections is absent. Legacy shape: title→label, defaultCollapsed→collapsed.
ObjectFormSchema keys fall into three classes (#2545):
Spec-aligned — same name and semantics as @objectstack/specFormViewSchema: 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).
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.
Field whose values become the lanes (maps to column ids).
swimlaneField
string
Field for swimlane rows (2D grouping).
cardTitle
string
Field used as the card title.
cardFields
string[]
Fields rendered on each card.
data
any[]
Inline records, bucketed into lanes by groupBy.
limit
number
Fetch window for the board (default 100).
columns
KanbanColumn[]
Lanes, each with id, title, cards, and optional limit / className / collapsed. A card has id, title, optional description and badges.
quickAdd
boolean
Show a Quick Add button at the bottom of each column.
coverImageField
string
Field whose URL renders as the card cover image.
allowCollapse
boolean
Allow columns to be collapsed.
conditionalFormatting
KanbanConditionalFormattingRule[]
Card colouring rules — native { field, operator, value } or spec { condition, style }.
cardTemplates
CardTemplate[]
Predefined quick-add templates.
columnWidths
ColumnWidthConfig
Column width configuration.
grouping
GroupingConfig
ListView grouping config; its first field is the swimlane fallback.
onCardMove
function
Runtime slot supplied by a React host, (cardId, fromColumnId, toColumnId, newIndex); not authorable in JSON.
onCardClick
function
Runtime 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.
onQuickAdd
function
Runtime 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.
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).
Records rendered as events — an array, or a binding expression that resolves to one.
titleField
string
Record field for the event title. Default "title".
startDateField
string
Record field for the event start date/time. Default "start".
endDateField
string
Record field for the event end date/time. Default "end".
allDayField
string
Record field for the all-day flag. Default "allDay".
colorField
string
Record field for the event color. Default "color".
view
CalendarViewMode
View mode: "month", "week", "day" — the full union. "agenda" was retired in objectui#5740 and now fails validation. Default "month".
currentDate
string | Date
Initial calendar date — an ISO date string when authored as JSON.
allowCreate
boolean
Show the "New event" affordance; clicking it dispatches a create action. Default false.
onEventClick
function
Host-only: forwarded when a React host supplies a function; authored JSON cannot produce one.
onViewChange
function
Host-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.
// Layoutimport type { PageNodeSchema, DivSchema, CardSchema, GridSchema, TabsSchema } from '@object-ui/types';// Formsimport type { FormSchema, InputSchema, SelectSchema, ButtonSchema } from '@object-ui/types';// Data Displayimport type { TableSchema, ChartSchema, TreeViewSchema } from '@object-ui/types';// CRUDimport type { ActionSchema, DetailSchema } from '@object-ui/types';// ObjectQLimport type { ObjectGridSchema, ObjectFormSchema, ObjectViewSchema } from '@object-ui/types';// Compleximport type { KanbanSchema, DashboardComponentSchema, CalendarViewSchema } from '@object-ui/types';// Viewsimport type { DetailViewSchema, ViewSwitcherSchema } from '@object-ui/types';// Baseimport type { BaseSchema, SchemaNode } from '@object-ui/types';