ObjectStackObjectStack

Component

Component protocol schemas

Empty Properties Schema

Source: packages/spec/src/ui/component.zod.ts

TypeScript Usage

import { AIChatWindowProps, ElementButtonPropsSchema, ElementFilterPropsSchema, ElementFormPropsSchema, ElementImagePropsSchema, ElementMetadataViewerPropsSchema, ElementNumberPropsSchema, ElementRecordPickerPropsSchema, ElementTextInputPropsSchema, ElementTextPropsSchema, ObjectCalendarPropsSchema, ObjectFormPropsSchema, ObjectGridPropsSchema, ObjectKanbanPropsSchema, ObjectMasterDetailFormPropsSchema, ObjectMetricPropsSchema, PageAccordionProps, PageCardProps, PageContainerProps, PageHeaderProps, PageTabsProps, RecordActivityProps, RecordAlertActionSchema, RecordAlertProps, RecordChatterProps, RecordDetailsProps, RecordHighlightsField, RecordHighlightsProps, RecordHistoryProps, RecordPathProps, RecordQuickActionsProps, RecordReferenceRailProps, RecordRelatedListProps, ReferenceRailEntrySchema } from '@objectstack/spec/ui';
import type { ElementNumberProps, ElementRecordPickerProps, ObjectCalendarProps, ObjectFormProps, ObjectGridProps, ObjectKanbanProps, ObjectMasterDetailFormProps, ObjectMetricProps, PageContainerProps, RecordAlertAction, RecordAlertProps, RecordHighlightsField, RecordHistoryProps, RecordPathProps, RecordQuickActionsProps, RecordReferenceRailProps, ReferenceRailEntry } from '@objectstack/spec/ui';

// Validate data
const result = AIChatWindowProps.parse(data);

AIChatWindowProps

Properties

PropertyTypeRequiredDescription
modeEnum<'float' | 'sidebar' | 'inline'>optional (default: "float")Display mode for the chat window
agentIdstringoptionalSpecific AI agent to use
contextRecord<string, any>optionalContextual data to pass to the AI
aria{ ariaLabel?: string | Record<string, string>; ariaDescribedBy?: string; role?: string }optionalARIA accessibility attributes

Nested Shape: AIChatWindowProps.aria

PropertyTypeRequiredDescription
ariaLabelstring | Record<string, string>optionalAccessible label for screen readers (WAI-ARIA aria-label). Plain string, or an inline locale map — no translation-bundle slot addresses this key, so a plain string is announced in the source language.
ariaDescribedBystringoptionalID of element providing additional description (WAI-ARIA aria-describedby)
rolestringoptionalWAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")

ElementButtonProps

Properties

PropertyTypeRequiredDescription
labelstring | Record<string, string>Button display label
variantEnum<'primary' | 'secondary' | 'danger' | 'ghost' | 'link'>optional (default: "primary")Button visual variant
sizeEnum<'small' | 'medium' | 'large'>optional (default: "medium")Button size
iconstringoptionalLucide icon name rendered inside the button, left or right of the label per iconPosition. Read on this component — the renderer resolves it through lucide-react's icons map via the shared resolveIcon helper every action:* site uses (a PascalCase normaliser plus a one-entry rename map), NOT the LazyIcon slot the container icons use; the two paths accept different spellings, and an unknown name here renders nothing rather than a fallback glyph.
iconPositionEnum<'left' | 'right'>optional (default: "left")Icon position relative to label
disabledbooleanoptional (default: false)Disable the button
action{ type?: Enum<'script' | 'url' | 'modal' | 'flow' | 'api' | 'form'>; name?: string; label?: string | Record<string, string>; target?: string; … }optionalInline action executed on click
aria{ ariaLabel?: string | Record<string, string>; ariaDescribedBy?: string; role?: string }optionalARIA accessibility attributes

Nested Shape: ElementButtonProps.action

PropertyTypeRequiredDescription
typeEnum<'script' | 'url' | 'modal' | 'flow' | 'api' | 'form'>optional (default: "script")Action functionality type
namestringoptionalMachine name (lowercase snake_case)
labelstring | Record<string, string>optionalDisplay label
targetstringoptionalURL, Script Name, Flow ID, or API Endpoint. Supports ${param.X} and ${ctx.X} interpolation.
openInEnum<'self' | 'new-tab'>optionalFor type:'url' — where to open target. 'new-tab' opens a new browser tab; 'self' navigates in place. When omitted, external/absolute URLs open in a new tab and relative URLs navigate in place. Static execution option — keep it OUT of params (which is user-input-collection only).
methodEnum<'POST' | 'PATCH' | 'PUT' | 'DELETE'>optionalHTTP method for type:"api" actions. Defaults to POST.
params{ name?: string; field?: string; objectOverride?: string; label?: string | Record<string, string>; … }[]optionalInput parameters required from user — an ActionParam[] DEFINITION array, never a payload map (a static request body goes in bodyExtra).
bodyExtraRecord<string, any>optionalStatic request-body fields for a type:"api" action, merged last (overrides user params). {{page.<var>}} tokens are resolved by the runtime. This — not params — is where a payload goes.
confirmTextstring | Record<string, string>optionalConfirmation message before execution. On a registered action, pairing this with a non-empty params is refused — that opens a second dialog for one decision; put the question on description instead. Correct on a param-LESS action, where the confirm is the only dialog there is.
successMessagestring | Record<string, string>optionalSuccess message to show after execution
errorMessagestring | Record<string, string>optionalError message to show when the action fails (overrides the raw error).
refreshAfterbooleanoptional (default: false)Refresh view after execution
opensInNewTabbooleanoptionalOpen the action result in a new tab. The renderer pre-opens the tab synchronously on click (popup-blocker-safe) and navigates it to the handler's redirectUrl.

Nested Shape: ElementButtonProps.aria

PropertyTypeRequiredDescription
ariaLabelstring | Record<string, string>optionalAccessible label for screen readers (WAI-ARIA aria-label). Plain string, or an inline locale map — no translation-bundle slot addresses this key, so a plain string is announced in the source language.
ariaDescribedBystringoptionalID of element providing additional description (WAI-ARIA aria-describedby)
rolestringoptionalWAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")

ElementFilterProps

Properties

PropertyTypeRequiredDescription
objectneveroptional[REMOVED] element:filter property object was removed in @objectstack/spec 17 (ADR-0049) — the whole element:filter element is retired: no renderer for it ever shipped in objectui, framework or cloud (Studio's designer palette lists it as a no-renderer exclusion), so every key on this element was a capability claim nothing kept. Delete the element:filter component; list surfaces own their filtering — use a view's userFilters quick-filter bar or the list toolbar's filter builder. Run os migrate meta --from 17 to list the mechanical edits for existing sources; apply them by hand.
fieldsneveroptional[REMOVED] element:filter property fields was removed in @objectstack/spec 17 (ADR-0049) — the whole element:filter element is retired: no renderer for it ever shipped in objectui, framework or cloud (Studio's designer palette lists it as a no-renderer exclusion), so every key on this element was a capability claim nothing kept. Delete the element:filter component; list surfaces own their filtering — use a view's userFilters quick-filter bar or the list toolbar's filter builder. Run os migrate meta --from 17 to list the mechanical edits for existing sources; apply them by hand.
targetVariableneveroptional[REMOVED] element:filter property targetVariable was removed in @objectstack/spec 17 (ADR-0049) — the whole element:filter element is retired: no renderer for it ever shipped in objectui, framework or cloud (Studio's designer palette lists it as a no-renderer exclusion), so every key on this element was a capability claim nothing kept. Delete the element:filter component; list surfaces own their filtering — use a view's userFilters quick-filter bar or the list toolbar's filter builder. Run os migrate meta --from 17 to list the mechanical edits for existing sources; apply them by hand.
layoutneveroptional[REMOVED] element:filter property layout was removed in @objectstack/spec 17 (ADR-0049) — the whole element:filter element is retired: no renderer for it ever shipped in objectui, framework or cloud (Studio's designer palette lists it as a no-renderer exclusion), so every key on this element was a capability claim nothing kept. Delete the element:filter component; list surfaces own their filtering — use a view's userFilters quick-filter bar or the list toolbar's filter builder. Run os migrate meta --from 17 to list the mechanical edits for existing sources; apply them by hand.
showSearchneveroptional[REMOVED] element:filter property showSearch was removed in @objectstack/spec 17 (ADR-0049) — the whole element:filter element is retired: no renderer for it ever shipped in objectui, framework or cloud (Studio's designer palette lists it as a no-renderer exclusion), so every key on this element was a capability claim nothing kept. Delete the element:filter component; list surfaces own their filtering — use a view's userFilters quick-filter bar or the list toolbar's filter builder. Run os migrate meta --from 17 to list the mechanical edits for existing sources; apply them by hand.
arianeveroptional[REMOVED] element:filter property aria was removed in @objectstack/spec 17 (ADR-0049) — the whole element:filter element is retired: no renderer for it ever shipped in objectui, framework or cloud (Studio's designer palette lists it as a no-renderer exclusion), so every key on this element was a capability claim nothing kept. Delete the element:filter component; list surfaces own their filtering — use a view's userFilters quick-filter bar or the list toolbar's filter builder. Run os migrate meta --from 17 to list the mechanical edits for existing sources; apply them by hand.

ElementFormProps

Properties

PropertyTypeRequiredDescription
objectneveroptional[REMOVED] element:form property object was removed in @objectstack/spec 17 (ADR-0049) — the whole element:form element is retired: no renderer for it ever shipped in objectui, framework or cloud (Studio's designer palette lists it as a no-renderer exclusion — "use the object-bound object-form block"), so every key on this element was a capability claim nothing kept. Delete the element:form component and use the object-bound object-form block instead — it is rendered, designer-publishable, and carries the same intent (objectName, fields, mode, submitText). Run os migrate meta --from 17 to list the mechanical edits for existing sources; apply them by hand.
fieldsneveroptional[REMOVED] element:form property fields was removed in @objectstack/spec 17 (ADR-0049) — the whole element:form element is retired: no renderer for it ever shipped in objectui, framework or cloud (Studio's designer palette lists it as a no-renderer exclusion — "use the object-bound object-form block"), so every key on this element was a capability claim nothing kept. Delete the element:form component and use the object-bound object-form block instead — it is rendered, designer-publishable, and carries the same intent (objectName, fields, mode, submitText). Run os migrate meta --from 17 to list the mechanical edits for existing sources; apply them by hand.
modeneveroptional[REMOVED] element:form property mode was removed in @objectstack/spec 17 (ADR-0049) — the whole element:form element is retired: no renderer for it ever shipped in objectui, framework or cloud (Studio's designer palette lists it as a no-renderer exclusion — "use the object-bound object-form block"), so every key on this element was a capability claim nothing kept. Delete the element:form component and use the object-bound object-form block instead — it is rendered, designer-publishable, and carries the same intent (objectName, fields, mode, submitText). Run os migrate meta --from 17 to list the mechanical edits for existing sources; apply them by hand.
submitLabelneveroptional[REMOVED] element:form property submitLabel was removed in @objectstack/spec 17 (ADR-0049) — the whole element:form element is retired: no renderer for it ever shipped in objectui, framework or cloud (Studio's designer palette lists it as a no-renderer exclusion — "use the object-bound object-form block"), so every key on this element was a capability claim nothing kept. Delete the element:form component and use the object-bound object-form block instead — it is rendered, designer-publishable, and carries the same intent (objectName, fields, mode, submitText). Run os migrate meta --from 17 to list the mechanical edits for existing sources; apply them by hand.
onSubmitneveroptional[REMOVED] element:form property onSubmit was removed in @objectstack/spec 17 (ADR-0049) — the whole element:form element is retired: no renderer for it ever shipped in objectui, framework or cloud (Studio's designer palette lists it as a no-renderer exclusion — "use the object-bound object-form block"), so every key on this element was a capability claim nothing kept. Delete the element:form component and use the object-bound object-form block instead — it is rendered, designer-publishable, and carries the same intent (objectName, fields, mode, submitText). Run os migrate meta --from 17 to list the mechanical edits for existing sources; apply them by hand.
arianeveroptional[REMOVED] element:form property aria was removed in @objectstack/spec 17 (ADR-0049) — the whole element:form element is retired: no renderer for it ever shipped in objectui, framework or cloud (Studio's designer palette lists it as a no-renderer exclusion — "use the object-bound object-form block"), so every key on this element was a capability claim nothing kept. Delete the element:form component and use the object-bound object-form block instead — it is rendered, designer-publishable, and carries the same intent (objectName, fields, mode, submitText). Run os migrate meta --from 17 to list the mechanical edits for existing sources; apply them by hand.

ElementImageProps

Properties

PropertyTypeRequiredDescription
srcstringImage URL or attachment field
altstringoptionalAlt text for accessibility
fitEnum<'cover' | 'contain' | 'fill'>optional (default: "cover")Image object-fit mode
heightnumberoptionalFixed height in pixels
aria{ ariaLabel?: string | Record<string, string>; ariaDescribedBy?: string; role?: string }optionalARIA accessibility attributes

Nested Shape: ElementImageProps.aria

PropertyTypeRequiredDescription
ariaLabelstring | Record<string, string>optionalAccessible label for screen readers (WAI-ARIA aria-label). Plain string, or an inline locale map — no translation-bundle slot addresses this key, so a plain string is announced in the source language.
ariaDescribedBystringoptionalID of element providing additional description (WAI-ARIA aria-describedby)
rolestringoptionalWAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")

ElementMetadataViewerProps

Properties

PropertyTypeRequiredDescription
typeEnum<'state_machine' | 'flow' | 'permission'>Metadata view kind (ADR-0051): state_machine | flow | permission
namestringTarget metadata item name; resolved package-scoped (ADR-0048), then dependencies (ADR-0046 §3.3)
objectstringoptionalOwning object — required for object-scoped kinds: state_machine is a rule ON an object (ADR-0020), permission renders a matrix FOR one; omit for top-level flow
modeEnum<'diagram' | 'matrix' | 'summary'>optionalRender form; defaults per type (diagram for flow/state_machine, matrix for permission)
detailEnum<'business' | 'technical'>optional (default: "business")Authoring altitude (ADR-0051 §3.4): business collapses technical flow nodes to business steps + approvals. NOT access (cf. book.audience); permission projection is automatic and render-time, never set here
aria{ ariaLabel?: string | Record<string, string>; ariaDescribedBy?: string; role?: string }optionalARIA accessibility attributes

Nested Shape: ElementMetadataViewerProps.aria

PropertyTypeRequiredDescription
ariaLabelstring | Record<string, string>optionalAccessible label for screen readers (WAI-ARIA aria-label). Plain string, or an inline locale map — no translation-bundle slot addresses this key, so a plain string is announced in the source language.
ariaDescribedBystringoptionalID of element providing additional description (WAI-ARIA aria-describedby)
rolestringoptionalWAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")

ElementNumberProps

Properties

PropertyTypeRequiredDescription
objectstringSource object
fieldstringoptionalField to aggregate
aggregateEnum<'count' | 'sum' | 'avg' | 'min' | 'max'>Aggregation function
filteranyoptionalFilter criteria
formatEnum<'number' | 'currency' | 'percent'>optionalNumber display format
prefixstringoptionalPrefix text (e.g. "$")
suffixstringoptionalSuffix text (e.g. "%")
aria{ ariaLabel?: string | Record<string, string>; ariaDescribedBy?: string; role?: string }optionalARIA accessibility attributes

Nested Shape: ElementNumberProps.aria

PropertyTypeRequiredDescription
ariaLabelstring | Record<string, string>optionalAccessible label for screen readers (WAI-ARIA aria-label). Plain string, or an inline locale map — no translation-bundle slot addresses this key, so a plain string is announced in the source language.
ariaDescribedBystringoptionalID of element providing additional description (WAI-ARIA aria-describedby)
rolestringoptionalWAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")

ElementRecordPickerProps

Properties

PropertyTypeRequiredDescription
objectstringObject to pick records from
labelFieldstringoptionalField rendered as each row's text (default name)
valueFieldstringoptionalField whose value is written into the bound page variable (default id)
labelstring | Record<string, string>optionalControl label rendered above the select
filteranyoptionalFilter criteria for available records
sort{ field: string; order: Enum<'asc' | 'desc'> }[]optionalRow order — synonym of the component-level dataSource.sort, which takes precedence when both are set
limitintegeroptionalMax records offered — synonym of the component-level dataSource.limit, which takes precedence when both are set (renderer default 50)
targetVariableneveroptional[REMOVED] element:record_picker property targetVariable was removed in @objectstack/spec 17 (ADR-0049) — it was a declarative hint no renderer ever read: the live binding runs the other direction, resolved from the page variable whose source names this component's id, so authoring only targetVariable bound nothing while reporting success. Delete the key; to bind the picked record id, declare it on the variable — variables: [{ name: '<var>', type: 'record_id', source: '<this component id>' }]. Run os migrate meta --from 17 to list the mechanical edits for existing sources; apply them by hand.
placeholderstring | Record<string, string>optionalPlaceholder text
emptyTextstring | Record<string, string>optionalText shown when the query returns no records (default "No records")
displayFieldneveroptional[REMOVED] element:record_picker property displayField was removed in @objectstack/spec 17.0.0 (ADR-0087 D2) — it was a required declaration no renderer ever read, while the renderer honoured labelField for the same thing and defaulted to name. Rename the key to labelField; the value (a field name) is unchanged. Run os migrate meta --from 16 to list the mechanical edits for existing sources; apply them by hand.
searchFieldsneveroptional[REMOVED] element:record_picker property searchFields was removed in @objectstack/spec 17.0.0 (ADR-0049) — the picker renders a plain single-select with no search input, so no renderer ever read it and it narrowed nothing. Delete the key. To restrict which records the picker offers, use filter (or the component-level dataSource.filter), which the query path does apply. Run os migrate meta --from 16 to list the mechanical edits for existing sources; apply them by hand.
multipleneveroptional[REMOVED] element:record_picker property multiple was removed in @objectstack/spec 17.0.0 (ADR-0049) — the picker is a single-select Select and the bound page variable holds one record id, so multiple: true selected nothing extra and reported success. Delete the key; multi-record selection is not implemented on this element. Run os migrate meta --from 16 to list the mechanical edits for existing sources; apply them by hand.
aria{ ariaLabel?: string | Record<string, string>; ariaDescribedBy?: string; role?: string }optionalARIA accessibility attributes

Nested Shape: ElementRecordPickerProps.sort[number]

Sort field and direction pair

PropertyTypeRequiredDescription
fieldstringField name to sort by
orderEnum<'asc' | 'desc'>Sort direction

Nested Shape: ElementRecordPickerProps.aria

PropertyTypeRequiredDescription
ariaLabelstring | Record<string, string>optionalAccessible label for screen readers (WAI-ARIA aria-label). Plain string, or an inline locale map — no translation-bundle slot addresses this key, so a plain string is announced in the source language.
ariaDescribedBystringoptionalID of element providing additional description (WAI-ARIA aria-describedby)
rolestringoptionalWAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")

ElementTextInputProps

Properties

PropertyTypeRequiredDescription
inputTypeEnum<'text' | 'email' | 'number' | 'tel' | 'url' | 'password'>optional (default: "text")Native input type — drives keyboard/validation affordance and how the bound value is coerced (number → numeric).
labelstring | Record<string, string>optionalField label shown above the input
placeholderstring | Record<string, string>optionalPlaceholder text shown when empty
defaultValuestring | numberoptionalInitial value; seeds the bound page variable on mount
requiredbooleanoptional (default: false)Mark the field as required
disabledbooleanoptional (default: false)Disable the input
descriptionstring | Record<string, string>optionalHelper text shown below the input
targetVariableneveroptional[REMOVED] element:text_input property targetVariable was removed in @objectstack/spec 17 (ADR-0049) — it was a declarative hint no renderer ever read: the live binding runs the other direction, resolved from the page variable whose source names this component's id, so authoring only targetVariable bound nothing while reporting success. Delete the key; to bind the typed value, declare it on the variable — variables: [{ name: '<var>', type: 'string', source: '<this component id>' }]. Run os migrate meta --from 17 to list the mechanical edits for existing sources; apply them by hand.
aria{ ariaLabel?: string | Record<string, string>; ariaDescribedBy?: string; role?: string }optionalARIA accessibility attributes

Nested Shape: ElementTextInputProps.aria

PropertyTypeRequiredDescription
ariaLabelstring | Record<string, string>optionalAccessible label for screen readers (WAI-ARIA aria-label). Plain string, or an inline locale map — no translation-bundle slot addresses this key, so a plain string is announced in the source language.
ariaDescribedBystringoptionalID of element providing additional description (WAI-ARIA aria-describedby)
rolestringoptionalWAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")

ElementTextProps

Properties

PropertyTypeRequiredDescription
contentstring | Record<string, string>Text or Markdown content — a plain string, or an inline locale map
variantEnum<'heading' | 'subheading' | 'body' | 'caption'>optional (default: "body")Text style variant
alignEnum<'left' | 'center' | 'right'>optional (default: "left")Text alignment
aria{ ariaLabel?: string | Record<string, string>; ariaDescribedBy?: string; role?: string }optionalARIA accessibility attributes

Nested Shape: ElementTextProps.aria

PropertyTypeRequiredDescription
ariaLabelstring | Record<string, string>optionalAccessible label for screen readers (WAI-ARIA aria-label). Plain string, or an inline locale map — no translation-bundle slot addresses this key, so a plain string is announced in the source language.
ariaDescribedBystringoptionalID of element providing additional description (WAI-ARIA aria-describedby)
rolestringoptionalWAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")

ObjectCalendarProps

Properties

PropertyTypeRequiredDescription
objectNamestringoptionalObject this calendar binds to. Optional because the component-level dataSource binding can supply the object instead
calendaranyoptionalCalendar field config: { startDateField, endDateField?, titleField?, colorField?, allDayField? }
defaultViewEnum<'month' | 'week' | 'day'>optionalInitial view mode
filteranyoptionalBase query filter
sortanyoptionalSort for the fetched events
dataany[]optionalPre-fetched records — skips the internal fetch
staticDataany[]optionalStatic inline records
localestringoptionalLocale override for the calendar chrome
loadingbooleanoptionalExternal loading state (honoured only alongside data)

ObjectFormProps

Properties

PropertyTypeRequiredDescription
objectNamestringoptionalObject this form creates/edits. Optional because the component-level dataSource binding can supply the object instead
recordIdstring | numberoptionalRecord to load (edit/view modes)
modeEnum<'create' | 'edit' | 'view'>optionalForm mode
formTypeEnum<'simple' | 'tabbed' | 'wizard' | 'split' | 'drawer' | 'modal'>optionalForm presentation
layoutEnum<'vertical' | 'horizontal' | 'inline' | 'grid'>optionalField layout
columnsnumberoptionalField columns in grid layout
fieldsany[]optionalLimit/order the fields shown
customFieldsanyoptionalCustom field definitions merged into the generated set
sectionsany[]optionalForm sections ({ label, description?, fields } — wizard steps / tab panes)
titlestring | Record<string, string>optionalForm title
descriptionstring | Record<string, string>optionalForm description (rendered by the drawer/modal presentations)
defaultTabstringoptionalInitially active tab (tabbed)
tabPositionEnum<'top' | 'bottom' | 'left' | 'right'>optionalTab strip position (tabbed)
allowSkipbooleanoptionalAllow skipping steps (wizard)
showStepIndicatorbooleanoptionalShow the step indicator (wizard)
splitDirectionEnum<'horizontal' | 'vertical'>optionalSplit direction (split)
splitSizenumberoptionalSplit panel size in percent (split)
splitResizablebooleanoptionalAllow resizing the split (split)
drawerSideEnum<'top' | 'bottom' | 'left' | 'right'>optionalDrawer side (drawer)
drawerWidthstring | numberoptionalDrawer width (drawer)
modalSizeEnum<'sm' | 'default' | 'lg' | 'xl' | 'full'>optionalModal size (modal)
modalCloseButtonbooleanoptionalShow the modal close button (modal)
contentLayoutanyoptionalModal content layout config (modal)
confirmOnDiscardbooleanoptionalConfirm before discarding edits (drawer/modal)
submitTextstring | Record<string, string>optionalSubmit button label
cancelTextstring | Record<string, string>optionalCancel button label
nextTextstring | Record<string, string>optionalNext-step button label (wizard)
prevTextstring | Record<string, string>optionalPrevious-step button label (wizard)
showSubmitbooleanoptionalShow the submit button
showCancelbooleanoptionalShow the cancel button
showResetbooleanoptionalShow the reset button
submitBehavioranyoptionalWhat happens after a successful submit ({ kind: 'thank-you' | …, title?, message? })
successMessagestring | Record<string, string>optionalToast message on successful submit
resetOnSuccessbooleanoptionalReset the form after a successful submit
navigateOnSuccessanyoptionalNavigate after a successful submit
readOnlybooleanoptionalRender every field read-only
initialValuesRecord<string, any>optionalPrefill values (create mode)
initialDataRecord<string, any>optionalAlternate spelling of initialValues the renderer also reads
mobileanyoptionalMobile presentation overrides

ObjectGridProps

Properties

PropertyTypeRequiredDescription
objectNamestringoptionalObject this grid binds to. Optional because the component-level dataSource binding can supply the object instead
labelstring | Record<string, string>optionalGrid label — used as the table caption and export file title
titlestring | Record<string, string>optionalFallback for label (the renderer reads label || title)
columnsany[]optionalColumns: field names or column definition objects
fieldsany[]optionalField list fallback used when columns is absent
filteranyoptionalBase query filter (ObjectQL filter array/AST) — lowered to the wire $filter. THE key, singular — not the plural misspelling
defaultFiltersanyoptionalLegacy base-filter fallback, read only when filter is absent. Prefer filter
sortanyoptionalInitial sort (array of { field, order })
defaultSortneveroptional[REMOVED] object-grid property defaultSort was removed in @objectstack/spec 17 (ADR-0049) — it was the legacy second spelling of sort: a single { field, order } pair read only when sort was absent, so one intent had two spellings and a grid authoring both silently ignored this one. Rename the key to sort and wrap the value in an array (defaultSort: { field, order } becomes sort: [{ field, order }]); the pair itself is unchanged. Run os migrate meta --from 17 to list the mechanical edits for existing sources; apply them by hand.
paginationanyoptionalPagination config ({ pageSize, pageSizeOptions, … }); its presence enables paging
pageSizenumberoptionalFlat page-size shorthand; pagination.pageSize wins when both are set
showPaginationbooleanoptionalShow the pager (read only when pagination is absent)
searchableFieldsstring[]optionalFields the toolbar search queries; a non-empty list enables search
showSearchbooleanoptionalShow the search box (read only when searchableFields is absent)
rowHeightanyoptionalRow density mode (e.g. compact / comfortable)
groupinganyoptionalRow grouping config
aggregationsanyoptionalGroup aggregation config (sum/avg/… per column)
conditionalFormattinganyoptionalConditional row/cell formatting rules
rowColoranyoptionalRow color rules
selectionanyoptionalSelection config ({ type: none | single | multiple })
selectableanyoptionalLegacy selection shorthand, read only when selection is absent. Prefer selection
rowActionsany[]optionalPer-row action names
bulkActionsany[]optionalBulk action names shown on selection
batchActionsany[]optionalAlternate spelling the renderer reads FIRST (batchActions ?? bulkActions)
bulkActionDefsany[]optionalInline bulk-action definitions (full defs, not names)
navigationanyoptionalRow-click navigation config ({ mode: page | drawer | modal | split | none })
editablebooleanoptionalEnable inline cell editing
singleClickEditbooleanoptionalEnter cell edit on single click (default true when editable)
resizablebooleanoptionalAllow column resize (read before resizableColumns)
resizableColumnsbooleanoptionalAlternate spelling of resizable (the renderer reads resizable ?? resizableColumns)
reorderableColumnsbooleanoptionalAllow column drag-reorder
frozenColumnsnumberoptionalHow many leading columns stay frozen (default 1)
showColumnTypeIconsbooleanoptionalShow field-type icons in column headers
exportOptionsanyoptionalExport config ({ formats, streaming })
operationsanyoptionalOperation toggles ({ export: false, … })
data{ provider: 'object'; object: string } | { provider: 'api'; read?: object; write?: object } | { provider: 'value'; items: any[] } | { provider: 'schema'; schemaId: string; schema?: Record<string, any> }optionalData source binding (ViewDataSchema — discriminated on provider: object | api | value | schema). Static inline rows live at { provider: 'value', items: [...] }; the bare-array shortcut is refused — see migration object-grid-data-view-data-converged
staticDataany[]optionalDeprecated bare-array static-rows shortcut the renderer still reads. Prefer data: { provider: 'value', items: [...] }

Nested Shape: ObjectGridProps.data[provider='object']

PropertyTypeRequiredDescription
provider'object'
objectstringTarget object name

Nested Shape: ObjectGridProps.data[provider='api']

PropertyTypeRequiredDescription
provider'api'
read{ url: string; method: Enum<'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'>; headers?: Record<string, string>; params?: Record<string, any>; … }optionalConfiguration for fetching data
write{ url: string; method: Enum<'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'>; headers?: Record<string, string>; params?: Record<string, any>; … }optionalConfiguration for submitting data (for forms/editable tables)

Nested Shape: ObjectGridProps.data[provider='value']

PropertyTypeRequiredDescription
provider'value'
itemsany[]Static data array

Nested Shape: ObjectGridProps.data[provider='schema']

PropertyTypeRequiredDescription
provider'schema'
schemaIdstringSchema identifier — typically the metadata type name
schemaRecord<string, any>optionalInline JSON Schema (Draft 2020-12). Optional when schemaId is resolvable.

ObjectKanbanProps

Properties

PropertyTypeRequiredDescription
objectNamestringoptionalObject this board binds to. Optional because the component-level dataSource binding can supply the object instead
groupBystringoptionalField whose values become the board columns
columnsany[]optionalSwimlane definitions ({ id, title } per groupBy value, or bare value strings) — NOT a field projection
filteranyoptionalBase query filter, handed to the wire $filter
dataany[]optionalStatic inline cards — bypasses the object query
cardTitlestringoptionalField rendered as each card title
titleFieldstringoptionalLegacy fallback for cardTitle (the board reads cardTitle || titleField). Prefer cardTitle
cardFieldsstring[]optionalFields rendered on each card
swimlaneFieldstringoptionalField for horizontal swimlanes (in addition to columns)
groupinganyoptionalView grouping config; its first field is the swimlane fallback
quickAddbooleanoptionalShow the per-column quick-add affordance
coverImageFieldstringoptionalImage field rendered as the card cover
conditionalFormattinganyoptionalCard conditional formatting rules

ObjectMasterDetailFormProps

Properties

PropertyTypeRequiredDescription
objectNamestringoptionalPARENT object. Optional because the component-level dataSource binding can supply the object instead
recordIdstring | numberoptionalParent record to load (edit mode)
modeEnum<'create' | 'edit'>optionalForm mode
formTypeEnum<'simple' | 'tabbed'>optionalParent form presentation — the two variants the renderer honours for the parent half
sectionsany[]optionalParent form sections
fieldsany[]optionalParent fields shown
detailsany[]optionalDetail collections ({ title, childObject, addLabel?, columns?, relationshipField? } — FK and columns auto-derive from child metadata)
titlestring | Record<string, string>optionalForm title
submitTextstring | Record<string, string>optionalSubmit button label
cancelTextstring | Record<string, string>optionalCancel button label
showSubmitbooleanoptionalShow the submit button
initialValuesRecord<string, any>optionalPrefill values for the parent (create mode)
initialDataRecord<string, any>optionalAlternate spelling of initialValues the renderer also reads
taxRateFieldstringoptionalChild field holding the per-line tax rate (line-items totals)

ObjectMetricProps

Properties

PropertyTypeRequiredDescription
objectNamestringoptionalObject this metric aggregates. Optional because the component-level dataSource binding can supply the object instead
labelstring | Record<string, string>optionalMetric label
descriptionstring | Record<string, string>optionalHelper text under the value
titlestring | Record<string, string>optionalDrill-down panel title; defaults to the metric label
iconstringoptionalLucide icon name drawn in the metric tile header, inside the colorVariant-tinted square. Read on this component — ObjectMetricWidget forwards it to MetricWidget, which resolves it with getLazyIcon (the LazyIcon module: kebab-case or PascalCase, degrading to the Database glyph on an unknown name).
colorVariantEnum<'default' | 'blue' | 'teal' | 'orange' | 'purple' | 'success' | 'warning' | 'danger'>optionalIcon container color variant
aggregateanyoptionalAggregation config ({ field, function, groupBy? }) run against the object
filteranyoptionalFilter the aggregation is scoped by
formatstringoptionalNumber format pattern (e.g. '0,0', '$0,0', '0%')
currencystringoptionalISO currency code (e.g. 'USD') — enables currency formatting
prefixstringoptionalStatic prefix before the formatted value
suffixstringoptionalStatic suffix after the formatted value
invertbooleanoptionalDisplay 1 - value for opposite-signal gauges (compliance/uptime)
variantEnum<'card' | 'bare'>optionalLayout variant
fallbackValuestring | numberoptionalStatic value shown when no data source is available
trendanyoptionalStatic trend info ({ value, label, direction })
drillDownanyoptionalClick-through drill config — opens the underlying records
compareToanyoptionalPeriod-over-period comparison ({ kind: 'previousPeriod' | 'previousYear' })

PageAccordionProps

Properties

PropertyTypeRequiredDescription
items{ label: string | Record<string, string>; icon?: string; collapsed: boolean; children: any[] }[]
allowMultiplebooleanoptional (default: false)Allow multiple panels to be expanded simultaneously
variantEnum<'flush' | 'card'>optional (default: "flush")Panel framing: 'flush' draws a divider under each panel; 'card' leaves the border to each panel's own content
aria{ ariaLabel?: string | Record<string, string>; ariaDescribedBy?: string; role?: string }optionalARIA accessibility attributes

Nested Shape: PageAccordionProps.items[number]

PropertyTypeRequiredDescription
labelstring | Record<string, string>Display label — the default-language string, or an inline locale map ({ en, "zh-CN" }) resolved at render time
iconstringoptionalLucide icon name rendered in the panel trigger, left of the label. Read on this component — the renderer draws it via LazyIcon; contrast the item value beside it, which the renderer overwrites with panel-<index>.
collapsedbooleanoptional (default: false)
childrenany[]Child components

Nested Shape: PageAccordionProps.aria

PropertyTypeRequiredDescription
ariaLabelstring | Record<string, string>optionalAccessible label for screen readers (WAI-ARIA aria-label). Plain string, or an inline locale map — no translation-bundle slot addresses this key, so a plain string is announced in the source language.
ariaDescribedBystringoptionalID of element providing additional description (WAI-ARIA aria-describedby)
rolestringoptionalWAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")

PageCardProps

Properties

PropertyTypeRequiredDescription
titlestring | Record<string, string>optionalDisplay label — the default-language string, or an inline locale map ({ en, "zh-CN" }) resolved at render time
borderedbooleanoptional (default: true)
actionsneveroptional[REMOVED] page:card property actions was removed in @objectstack/spec 17.0.0 (ADR-0087 D2) — no renderer ever read it: objectui's card renderer builds its <Card> from title, bordered, children and footer only, has no actions area, and the component registry never published it as an input, so an authored value was accepted and dropped. Delete the key and author the buttons as components in the card's children or footer (element:button, record:quick_actions), which is what actually renders. Run os migrate meta --from 16 to list the mechanical edits for existing sources; apply them by hand.
childrenany[]optionalCard content components, in order (the card body slot)
bodyneveroptional[REMOVED] page:card property body was removed in @objectstack/spec 17.0.0 (ADR-0087 D2) — it was a second spelling of the composition slot every other container calls children, and the renderer reads both. Rename the key to children; the value (an array of child components) is unchanged. Run os migrate meta --from 16 to list the mechanical edits for existing sources; apply them by hand.
footerany[]optionalCard footer components (slot)
aria{ ariaLabel?: string | Record<string, string>; ariaDescribedBy?: string; role?: string }optionalARIA accessibility attributes

Nested Shape: PageCardProps.aria

PropertyTypeRequiredDescription
ariaLabelstring | Record<string, string>optionalAccessible label for screen readers (WAI-ARIA aria-label). Plain string, or an inline locale map — no translation-bundle slot addresses this key, so a plain string is announced in the source language.
ariaDescribedBystringoptionalID of element providing additional description (WAI-ARIA aria-describedby)
rolestringoptionalWAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")

PageContainerProps

Properties

PropertyTypeRequiredDescription
childrenany[]optionalChild components rendered inside this container, in order

PageHeaderProps

Properties

PropertyTypeRequiredDescription
titlestring | Record<string, string>optionalPage title. Omit to let the renderer derive the heading from the record (the default for record pages) — set explicitly on non-record pages (dashboard, landing) with no record to derive from.
subtitlestring | Record<string, string>optionalPage subtitle
iconneveroptional[REMOVED] page:header property icon was removed in @objectstack/spec 17.0.0 (ADR-0087 D2) — no renderer ever read it: objectui resolves icon only per header action (action.icon), never off the header's own props bag, and the component registry never published it as an input, so an authored value was accepted and dropped. Delete the key. The header's own identity is drawn by the record chrome (recordChrome, on by default) and each action carries its own icon. Run os migrate meta --from 16 to list the mechanical edits for existing sources; apply them by hand.
breadcrumbbooleanoptional (default: true)Show breadcrumb
actionsstring[]optionalAction IDs to show in header
recordChromebooleanoptional (default: true)Render the record chrome — the title as a record chip with its follow star and copy-id button. Set false on a non-record page (dashboard, landing) to fall back to the bare heading layout.
showStarbooleanoptional (default: true)Show the follow (favourite) star beside the record title. Part of the record chrome — no effect when recordChrome is false.
showCopyIdbooleanoptional (default: true)Show the copy-record-id button beside the record title. Part of the record chrome — no effect when recordChrome is false.
maxVisibleintegeroptionalHow many header actions render as inline buttons before the rest fold into the overflow menu (renderer default 3).
mobileMaxVisibleintegeroptionalThe maxVisible budget on mobile viewports (renderer default 1).
aria{ ariaLabel?: string | Record<string, string>; ariaDescribedBy?: string; role?: string }optionalARIA accessibility attributes

Nested Shape: PageHeaderProps.aria

PropertyTypeRequiredDescription
ariaLabelstring | Record<string, string>optionalAccessible label for screen readers (WAI-ARIA aria-label). Plain string, or an inline locale map — no translation-bundle slot addresses this key, so a plain string is announced in the source language.
ariaDescribedBystringoptionalID of element providing additional description (WAI-ARIA aria-describedby)
rolestringoptionalWAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")

PageTabsProps

Properties

PropertyTypeRequiredDescription
tabStyleEnum<'line' | 'card' | 'pill'>optional (default: "line")Tab-strip visual style: 'line' underlines the active tab, 'card' frames each tab, 'pill' renders rounded pills
typeneveroptional[REMOVED] page:tabs property type was removed in @objectstack/spec 17.0.0 (ADR-0087 D2) — a props key named type collides with the page component's own dispatch key, so it is unauthorable in the flat and JSX carriers and was never validated in them. Rename the key to tabStyle; the value (line | card | pill) is unchanged. Run os migrate meta --from 16 to list the mechanical edits for existing sources; apply them by hand.
positionEnum<'top' | 'left'>optional (default: "top")
alwaysShowStripbooleanoptionalRender the tab strip even when only one tab is visible (renderer default: a one-tab strip is hidden).
items{ label: string | Record<string, string>; icon?: string; visibleWhen?: string | object; value?: string; … }[]
aria{ ariaLabel?: string | Record<string, string>; ariaDescribedBy?: string; role?: string }optionalARIA accessibility attributes

Nested Shape: PageTabsProps.items[number]

PropertyTypeRequiredDescription
labelstring | Record<string, string>Display label — the default-language string, or an inline locale map ({ en, "zh-CN" }) resolved at render time
iconstringoptionalLucide icon name rendered in the tab trigger, left of the label. Read on this component — the renderer draws it via LazyIcon; contrast the item key beside it, which no read point takes and which the alias table answers with value.
visibleWhenstring | { dialect: Enum<'cel' | 'cron' | 'template'>; source?: string; ast?: any; meta?: object }optionalVisibility predicate (CEL) — the whole tab (header + panel) is omitted when FALSE; the renderer falls back to the first visible tab when the active one is hidden. Contract-bound roots: record, current_user (ADR-0068 aliases user / ctx.user), page.<var>. ⚠️ NOT the same environment as page-component visibleWhen: this surface's own evaluator binds data to the record ROW (not the data-source adapter) and also spreads the row's bare fields — renderer behaviour, NOT contract-guaranteed. ADR-0089 canonical name — visible/showWhen/visibility/visibleOn are all rejected here (not folded in), each with a pointer at this key.
valuestringoptionalStable ?tab= URL token for this tab (default: index-derived tab-<i>, which is not durable across item-list changes)
countintegeroptionalBadge count shown next to the tab label (default: derived from record:related_list descendants)
childrenany[]Child components

Nested Shape: PageTabsProps.aria

PropertyTypeRequiredDescription
ariaLabelstring | Record<string, string>optionalAccessible label for screen readers (WAI-ARIA aria-label). Plain string, or an inline locale map — no translation-bundle slot addresses this key, so a plain string is announced in the source language.
ariaDescribedBystringoptionalID of element providing additional description (WAI-ARIA aria-describedby)
rolestringoptionalWAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")

RecordActivityProps

Properties

PropertyTypeRequiredDescription
types(Enum<'comment' | 'field_change' | 'task' | 'event' | 'email' | 'call' | 'note' | 'file' | 'record_create' | 'record_delete' | 'approval' | 'sharing' | 'system'> | string)[]optionalFeed item kinds to show (default: all). Open vocabulary: the FeedItemType members are the platform built-in kinds, and author-contributed activity kinds (open sys_activity.type vocabulary, ADR-0052 §5b.2) are equally legal — entries are never validated against the built-in set.
filterModeEnum<'all' | 'comments_only' | 'changes_only' | 'tasks_only'>optional (default: "all")Default activity filter
showFilterTogglebooleanoptional (default: true)Show filter dropdown in panel header
limitintegeroptional (default: 20)Number of items to load per page
showCompletedbooleanoptional (default: false)Include completed activities
unifiedTimelinebooleanoptional (default: true)Mix field changes and comments in one timeline (Airtable style)
showCommentInputbooleanoptional (default: true)Show "Leave a comment" input at the bottom
enableMentionsbooleanoptional (default: true)Enable @mentions in comments
enableReactionsbooleanoptional (default: false)Enable emoji reactions on feed items
enableThreadingbooleanoptional (default: false)Enable threaded replies on comments
showSubscriptionTogglebooleanoptional (default: true)Show bell icon for record-level notification subscription
aria{ ariaLabel?: string | Record<string, string>; ariaDescribedBy?: string; role?: string }optionalARIA accessibility attributes

Nested Shape: RecordActivityProps.aria

PropertyTypeRequiredDescription
ariaLabelstring | Record<string, string>optionalAccessible label for screen readers (WAI-ARIA aria-label). Plain string, or an inline locale map — no translation-bundle slot addresses this key, so a plain string is announced in the source language.
ariaDescribedBystringoptionalID of element providing additional description (WAI-ARIA aria-describedby)
rolestringoptionalWAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")

RecordAlertAction

Properties

PropertyTypeRequiredDescription
actionNamestringName of an action declared on this object (actions[]) — resolved from object metadata and run through the shared action engine, so confirm/param dialogs, toast and reload behave exactly as in record:quick_actions.
labelstring | Record<string, string>optionalCTA button label — a string or an inline locale map, resolved with the same pickLocalized chain as title/body (default: the action's own label).
variantEnum<'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link'>optionalButton variant — the Button primitive's own vocabulary (renderer default: destructive when severity is error, else default).

RecordAlertProps

Properties

PropertyTypeRequiredDescription
severityEnum<'info' | 'warning' | 'error' | 'success'>optionalBanner severity — styling, default icon, and the a11y role (error renders role="alert"/assertive; the rest role="status"/polite). Renderer default: info.
titlestring | Record<string, string>optionalBanner title — a string or an inline locale map ({ en, "zh-CN", … }), resolved to the current language at render (pickLocalized).
bodystring | Record<string, string>optionalBanner body — a string or an inline locale map, resolved like title.
visibleboolean | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source?: string; ast?: any; meta?: object }optionalVisibility predicate evaluated against the record page scope (record, user + ctx.* mirror, objectName, features) — a boolean literal, a CEL string, or a { dialect, source } envelope. Omit for always-visible; the banner is hidden while the record is still loading either way.
iconstringoptionalLucide icon name (renderer default: the severity's own icon). Read on this component — contrast the rail's refused icon, which no render path reads.
action{ actionName: string; label?: string | Record<string, string>; variant?: Enum<'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link'> }optionalOptional call-to-action button rendered under the body — { actionName, label?, variant? }, resolved from the object's declared actions.
dismissiblebooleanoptionalRender an X control; dismissal is remembered per object/record in localStorage (renderer default: off).
dismissKeystringoptionalStable key the dismissal is remembered under, so reworded titles do not resurrect a dismissed banner (renderer default: the English resolution of title, else the severity).

Nested Shape: RecordAlertProps.action

PropertyTypeRequiredDescription
actionNamestringName of an action declared on this object (actions[]) — resolved from object metadata and run through the shared action engine, so confirm/param dialogs, toast and reload behave exactly as in record:quick_actions.
labelstring | Record<string, string>optionalCTA button label — a string or an inline locale map, resolved with the same pickLocalized chain as title/body (default: the action's own label).
variantEnum<'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link'>optionalButton variant — the Button primitive's own vocabulary (renderer default: destructive when severity is error, else default).

RecordChatterProps

Properties

PropertyTypeRequiredDescription
positionEnum<'bottom' | 'right' | 'left'>optionalWhere the panel docks relative to the record body — right/left dock a side panel, bottom renders in flow under the record body (renderer default: bottom).
widthstring | numberoptionalPanel width (e.g., "350px", "30%") — side positions (right/left) only.
collapsiblebooleanoptionalWhether the panel can be collapsed (renderer default: off).
defaultCollapsedbooleanoptionalWhether the panel starts collapsed (renderer default: off; only meaningful with collapsible).
feed{ types?: (Enum<'comment' | 'field_change' | 'task' | 'event' | 'email' | 'call' | 'note' | …> | string)[]; filterMode: Enum<'all' | 'comments_only' | 'changes_only' | 'tasks_only'>; showFilterToggle: boolean; limit: integer; … }optionalEmbedded activity feed configuration
aria{ ariaLabel?: string | Record<string, string>; ariaDescribedBy?: string; role?: string }optionalARIA accessibility attributes

Nested Shape: RecordChatterProps.feed

PropertyTypeRequiredDescription
types(Enum<'comment' | 'field_change' | 'task' | 'event' | 'email' | 'call' | 'note' | …> | string)[]optionalFeed item kinds to show (default: all). Open vocabulary: the FeedItemType members are the platform built-in kinds, and author-contributed activity kinds (open sys_activity.type vocabulary, ADR-0052 §5b.2) are equally legal — entries are never validated against the built-in set.
filterModeEnum<'all' | 'comments_only' | 'changes_only' | 'tasks_only'>optional (default: "all")Default activity filter
showFilterTogglebooleanoptional (default: true)Show filter dropdown in panel header
limitintegeroptional (default: 20)Number of items to load per page
showCompletedbooleanoptional (default: false)Include completed activities
unifiedTimelinebooleanoptional (default: true)Mix field changes and comments in one timeline (Airtable style)
showCommentInputbooleanoptional (default: true)Show "Leave a comment" input at the bottom
enableMentionsbooleanoptional (default: true)Enable @mentions in comments
enableReactionsbooleanoptional (default: false)Enable emoji reactions on feed items
enableThreadingbooleanoptional (default: false)Enable threaded replies on comments
showSubscriptionTogglebooleanoptional (default: true)Show bell icon for record-level notification subscription
aria{ ariaLabel?: string | Record<string, string>; ariaDescribedBy?: string; role?: string }optionalARIA accessibility attributes

Nested Shape: RecordChatterProps.aria

PropertyTypeRequiredDescription
ariaLabelstring | Record<string, string>optionalAccessible label for screen readers (WAI-ARIA aria-label). Plain string, or an inline locale map — no translation-bundle slot addresses this key, so a plain string is announced in the source language.
ariaDescribedBystringoptionalID of element providing additional description (WAI-ARIA aria-describedby)
rolestringoptionalWAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")

RecordDetailsProps

Properties

PropertyTypeRequiredDescription
columnsEnum<'1' | '2' | '3' | '4'>optional (default: "2")Number of columns for field layout (1-4)
layoutneveroptional[REMOVED] record:details property layout was removed in @objectstack/spec 17.0.0 (ADR-0087 D2) — its declared auto | custom semantics were never implemented: the renderer tests layout only against inline | compact, two values the schema never permitted, so both legal values took the same branch and the key selected nothing. Delete the key — the body is already chosen by what you author: sections renders the explicit groups (the old custom), and omitting it falls back to the object's highlightFields (the old auto). Run os migrate meta --from 16 to list the mechanical edits for existing sources; apply them by hand.
sections{ name?: string; label?: string | Record<string, string>; columns?: integer; fields: string[]; … }[]optionalField groups rendered as the detail body, in order. Object form: { name?, label?, columns?, fields, hideEmpty?, collapsible?, showBorder?, defaultCollapsed?, icon?, description?, headerColor? }.
fieldsstring[]optionalExplicit field list to display (optional, overrides highlightFields)
hideFieldsstring[]optionalField names to omit from the body — applied to fields and to every section's fields (used to dedupe fields already shown in record:highlights or as the page title)
inlineEditbooleanoptionalAllow inline field editing in the detail body (renderer default: on, where the object itself is editable — set false to force it off).
showHeaderbooleanoptionalRender the detail body's own heading (renderer default: off).
aria{ ariaLabel?: string | Record<string, string>; ariaDescribedBy?: string; role?: string }optionalARIA accessibility attributes

Nested Shape: RecordDetailsProps.sections[number]

PropertyTypeRequiredDescription
namestringoptionalStable section identifier for i18n lookup (snake_case) — resolves objects.<object>._sections.<name>.label; a nameless section renders its authored label in every locale
labelstring | Record<string, string>optionalSection heading (omit for an untitled, borderless section)
columnsintegeroptionalField-grid columns for this section (1-4). Omitted → the renderer derives the width.
fieldsstring[]Field names rendered in this section, in order
hideEmptybooleanoptionalHide this section's empty fields (renderer default: on — and a section whose fields are ALL empty then renders nothing at all: no heading, no skeleton). Set false to render empty rows, keeping the section's label skeleton on an all-empty record (e.g. a brand-new one).
collapsiblebooleanoptionalRender this section as a collapsible card — the heading becomes a chevron toggle, initially expanded (renderer default: off).
showBorderbooleanoptionalDraw this section's card chrome (renderer default: derived — on for a titled section, off for an untitled one). Set false for a borderless titled section, or true for a bordered untitled one.
defaultCollapsedbooleanoptionalStart a collapsible: true section collapsed (renderer default: expanded). Consulted only when collapsible is on — a non-collapsible section never reads its collapse state.
iconstringoptionalHeading icon, as a lucide icon name (kebab-case, e.g. building-2). A value that is not an ASCII identifier (emoji, CJK text) renders as literal text beside the heading instead. Shown where the section heading renders: a titled section, or any collapsible section.
descriptionstringoptionalSub-heading text rendered under the section heading (plain string — the renderer applies no translation to it, unlike label). Renders on a titled or collapsible section; a collapsible section hides it while collapsed.
headerColorEnum<'muted' | 'muted/50' | 'accent' | 'primary/10' | 'secondary/10' | 'destructive/10'>optionalSection-header background tint, from the closed six-token vocabulary rendered by objectui's record:details header (muted | muted/50 | accent | primary/10 | secondary/10 | destructive/10). A value outside the enum is refused at authoring time rather than silently not painting. Omit for an untinted header.

Nested Shape: RecordDetailsProps.aria

PropertyTypeRequiredDescription
ariaLabelstring | Record<string, string>optionalAccessible label for screen readers (WAI-ARIA aria-label). Plain string, or an inline locale map — no translation-bundle slot addresses this key, so a plain string is announced in the source language.
ariaDescribedBystringoptionalID of element providing additional description (WAI-ARIA aria-describedby)
rolestringoptionalWAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")

RecordHighlightsField

Highlight field: bare name, or {name,label?,type?,readonly?}

Union Options

This schema accepts one of the following structures:

Option 1

Type: string


Option 2

Properties

PropertyTypeRequiredDescription
namestringField name on the record
labelstringoptionalDisplay label (overrides schema label)
typestringoptionalOverride cell renderer type (rare)
readonlybooleanoptionalRender this chip read-only — suppresses inline editing on the highlight card. Use for hook/automation-maintained columns that must not be hand-edited from the record header.


RecordHighlightsProps

Properties

PropertyTypeRequiredDescription
fields(string | { name: string; label?: string; type?: string; readonly?: boolean })[]Key fields to highlight (1-7 fields max, typically displayed as prominent cards). Each item may be a bare field name or {name, label?, type?, readonly?} for inline overrides.
layoutEnum<'horizontal' | 'vertical'>optional (default: "horizontal")Layout orientation for highlight fields
aria{ ariaLabel?: string | Record<string, string>; ariaDescribedBy?: string; role?: string }optionalARIA accessibility attributes

Nested Shape: RecordHighlightsProps.fields[number]

PropertyTypeRequiredDescription
namestringField name on the record
labelstringoptionalDisplay label (overrides schema label)
typestringoptionalOverride cell renderer type (rare)
readonlybooleanoptionalRender this chip read-only — suppresses inline editing on the highlight card. Use for hook/automation-maintained columns that must not be hand-edited from the record header.

Nested Shape: RecordHighlightsProps.aria

PropertyTypeRequiredDescription
ariaLabelstring | Record<string, string>optionalAccessible label for screen readers (WAI-ARIA aria-label). Plain string, or an inline locale map — no translation-bundle slot addresses this key, so a plain string is announced in the source language.
ariaDescribedBystringoptionalID of element providing additional description (WAI-ARIA aria-describedby)
rolestringoptionalWAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")

RecordHistoryProps

Properties

PropertyTypeRequiredDescription
limitintegeroptionalMaximum history entries displayed, and the $top of the self-fetch query (renderer default: 50).
emptyTextstringoptionalCopy shown when the record has no history. Literal string rendered as-is in EVERY locale (no inline locale map — the timeline renders it as a raw React child; renderer default: "No history yet").
unknownUserTextstringoptionalCopy substituted when an entry has no resolvable actor. Literal string, every locale (renderer default: "Unknown user").

RecordPathProps

Properties

PropertyTypeRequiredDescription
statusFieldstringField name representing the current status/stage
stages{ value: string; label: string | Record<string, string>; terminal?: Enum<'won' | 'lost'> }[]optionalExplicit stage definitions (if not using field metadata)
aria{ ariaLabel?: string | Record<string, string>; ariaDescribedBy?: string; role?: string }optionalARIA accessibility attributes

Nested Shape: RecordPathProps.stages[number]

PropertyTypeRequiredDescription
valuestring
labelstring | Record<string, string>Display label — the default-language string, or an inline locale map ({ en, "zh-CN" }) resolved at render time
terminalEnum<'won' | 'lost'>optionalMark this stage a terminus and its kind — overrides the renderer's value/label token heuristic

Nested Shape: RecordPathProps.aria

PropertyTypeRequiredDescription
ariaLabelstring | Record<string, string>optionalAccessible label for screen readers (WAI-ARIA aria-label). Plain string, or an inline locale map — no translation-bundle slot addresses this key, so a plain string is announced in the source language.
ariaDescribedBystringoptionalID of element providing additional description (WAI-ARIA aria-describedby)
rolestringoptionalWAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")

RecordQuickActionsProps

Properties

PropertyTypeRequiredDescription
actionNamesstring[]optionalNames of actions declared on this object (actions[]), in display order. The engine still location-filters named actions. Measured: when omitted (and the host supplies nothing) the bar resolves NO actions and renders its empty placeholder — it does not fall back to "every action at this location", whatever the registration's input list claims.
requiredPermissionsstring[]optionalHide the whole bar unless the current user holds every named permission on this object.
locationEnum<'list_toolbar' | 'list_item' | 'record_header' | 'record_more' | 'record_related' | 'record_section'>optionalWhich declared action location this bar renders (renderer default: record_header).
alignEnum<'start' | 'center' | 'end'>optionalHorizontal alignment of the button row (renderer default: end).
inlinebooleanoptionalRender in the flow instead of pulling up into the record-header band. The page header sets this itself when it hosts the bar in its own action slot.
variantEnum<'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link'>optionalButton variant for every action — the Button primitive's own vocabulary; a per-action variant on the resolved def wins (renderer default: default).
sizeEnum<'default' | 'sm' | 'lg' | 'icon'>optionalButton size for every action — the Button primitive's own vocabulary; a per-action size wins (renderer default: sm).

RecordReferenceRailProps

Properties

PropertyTypeRequiredDescription
entries{ objectName: string; relationshipField: string; title?: string; limit?: integer; … }[]Related collections to summarize — one compact card per entry (icon-less title, total-count badge, top-N preview rows). An empty rail renders nothing, so at least one entry is required.
hideEmptybooleanoptionalFold entries whose related count is 0 into a single "+ N empty" expander chip (renderer default: on; set false to always render every card).

Nested Shape: RecordReferenceRailProps.entries[number]

PropertyTypeRequiredDescription
objectNamestringRelated object name whose records this card summarizes (e.g. "task", "opportunity_quote")
relationshipFieldstringField on the related object that points back to this record (e.g. "account_id")
titlestringoptionalLiteral card title. Rendered as-is in EVERY locale (no inline locale map — the rail renders it as a raw React child); omit to use the related object's localized label.
limitintegeroptionalPreview rows per card, and the $top of the one query this entry issues (renderer default: 3).
displayFieldstringoptionalField of the related record rendered in each preview row (renderer fallback when omitted: name / title / subject / label / … / id).

RecordRelatedListProps

Properties

PropertyTypeRequiredDescription
objectNamestringRelated object name (e.g., "task", "opportunity")
relationshipFieldstringField on related object that points to this record (e.g., "account_id")
relationshipValueFieldstringoptional (default: "id")Parent-record field whose value relationshipField stores (default 'id'; e.g. 'name' for name-keyed junctions).
columnsstring[]optionalFields to display in the related list. Optional: when omitted, columns derive from the related object's highlightFields / default list columns (a related list is just another surface that lists that object). Override chain: child highlightFields → field-level relatedListColumns → this inline list.
sortstring | { field: string; order: Enum<'asc' | 'desc'> }[]optionalSort order for related records
limitintegeroptional (default: 5)Number of records to display initially
filter{ field: string; operator: Enum<'equals' | 'not_equals' | 'contains' | 'not_contains' | 'icontains' | …>; value?: string | number | boolean | null | (string | number)[] }[]optionalAdditional filter criteria for related records
titlestring | Record<string, string>optionalCustom title for the related list
showViewAllbooleanoptional (default: true)Show "View All" link to see all related records
actionsstring[]optionalAction IDs available for related records
add{ picker: object; linkField?: string; label?: string | Record<string, string> }optionalAdd-existing-via-picker config (generic m2m/junction assignment).
aria{ ariaLabel?: string | Record<string, string>; ariaDescribedBy?: string; role?: string }optionalARIA accessibility attributes

Nested Shape: RecordRelatedListProps.filter[number]

View filter rule

PropertyTypeRequiredDescription
fieldstringField name to filter on
operatorEnum<'equals' | 'not_equals' | 'contains' | 'not_contains' | 'icontains' | …>Filter operator
valuestring | number | boolean | null | (string | number)[]optionalFilter value. The accepted SHAPE depends on the operator: in / not_in take an array (any length, including []), between takes exactly [min, max], every other operator takes a scalar. The unary operators (is_empty / is_not_empty / is_null / is_not_null) take their direction from the operator name and ignore this key.

Nested Shape: RecordRelatedListProps.add

PropertyTypeRequiredDescription
picker{ object: string; valueField: string; labelField?: string; filter?: object[] }Where the Add affordance sources records from.
linkFieldstringoptionalField on objectName that stores the picked record id (junction case). Omit for a 1:m re-parent.
labelstring | Record<string, string>optionalLabel for the Add button (default "Add").

Nested Shape: RecordRelatedListProps.aria

PropertyTypeRequiredDescription
ariaLabelstring | Record<string, string>optionalAccessible label for screen readers (WAI-ARIA aria-label). Plain string, or an inline locale map — no translation-bundle slot addresses this key, so a plain string is announced in the source language.
ariaDescribedBystringoptionalID of element providing additional description (WAI-ARIA aria-describedby)
rolestringoptionalWAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")

ReferenceRailEntry

Properties

PropertyTypeRequiredDescription
objectNamestringRelated object name whose records this card summarizes (e.g. "task", "opportunity_quote")
relationshipFieldstringField on the related object that points back to this record (e.g. "account_id")
titlestringoptionalLiteral card title. Rendered as-is in EVERY locale (no inline locale map — the rail renders it as a raw React child); omit to use the related object's localized label.
limitintegeroptionalPreview rows per card, and the $top of the one query this entry issues (renderer default: 3).
displayFieldstringoptionalField of the related record rendered in each preview row (renderer fallback when omitted: name / title / subject / label / … / id).

On this page

TypeScript UsageAIChatWindowPropsPropertiesNested Shape: AIChatWindowProps.ariaElementButtonPropsPropertiesNested Shape: ElementButtonProps.actionNested Shape: ElementButtonProps.ariaElementFilterPropsPropertiesElementFormPropsPropertiesElementImagePropsPropertiesNested Shape: ElementImageProps.ariaElementMetadataViewerPropsPropertiesNested Shape: ElementMetadataViewerProps.ariaElementNumberPropsPropertiesNested Shape: ElementNumberProps.ariaElementRecordPickerPropsPropertiesNested Shape: ElementRecordPickerProps.sort[number]Nested Shape: ElementRecordPickerProps.ariaElementTextInputPropsPropertiesNested Shape: ElementTextInputProps.ariaElementTextPropsPropertiesNested Shape: ElementTextProps.ariaObjectCalendarPropsPropertiesObjectFormPropsPropertiesObjectGridPropsPropertiesNested Shape: ObjectGridProps.data[provider='object']Nested Shape: ObjectGridProps.data[provider='api']Nested Shape: ObjectGridProps.data[provider='value']Nested Shape: ObjectGridProps.data[provider='schema']ObjectKanbanPropsPropertiesObjectMasterDetailFormPropsPropertiesObjectMetricPropsPropertiesPageAccordionPropsPropertiesNested Shape: PageAccordionProps.items[number]Nested Shape: PageAccordionProps.ariaPageCardPropsPropertiesNested Shape: PageCardProps.ariaPageContainerPropsPropertiesPageHeaderPropsPropertiesNested Shape: PageHeaderProps.ariaPageTabsPropsPropertiesNested Shape: PageTabsProps.items[number]Nested Shape: PageTabsProps.ariaRecordActivityPropsPropertiesNested Shape: RecordActivityProps.ariaRecordAlertActionPropertiesRecordAlertPropsPropertiesNested Shape: RecordAlertProps.actionRecordChatterPropsPropertiesNested Shape: RecordChatterProps.feedNested Shape: RecordChatterProps.ariaRecordDetailsPropsPropertiesNested Shape: RecordDetailsProps.sections[number]Nested Shape: RecordDetailsProps.ariaRecordHighlightsFieldUnion OptionsOption 1Option 2PropertiesRecordHighlightsPropsPropertiesNested Shape: RecordHighlightsProps.fields[number]Nested Shape: RecordHighlightsProps.ariaRecordHistoryPropsPropertiesRecordPathPropsPropertiesNested Shape: RecordPathProps.stages[number]Nested Shape: RecordPathProps.ariaRecordQuickActionsPropsPropertiesRecordReferenceRailPropsPropertiesNested Shape: RecordReferenceRailProps.entries[number]RecordRelatedListPropsPropertiesNested Shape: RecordRelatedListProps.filter[number]Nested Shape: RecordRelatedListProps.addNested Shape: RecordRelatedListProps.ariaReferenceRailEntryProperties