Accessible 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.
ariaDescribedBy
string
optional
ID of element providing additional description (WAI-ARIA aria-describedby)
role
string
optional
WAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")
Lucide 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.
URL, Script Name, Flow ID, or API Endpoint. Supports ${param.X} and ${ctx.X} interpolation.
openIn
Enum<'self' | 'new-tab'>
optional
For 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).
method
Enum<'POST' | 'PATCH' | 'PUT' | 'DELETE'>
optional
HTTP method for type:"api" actions. Defaults to POST.
Input parameters required from user — an ActionParam[] DEFINITION array, never a payload map (a static request body goes in bodyExtra).
bodyExtra
Record<string, any>
optional
Static 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.
confirmText
string | Record<string, string>
optional
Confirmation 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.
successMessage
string | Record<string, string>
optional
Success message to show after execution
errorMessage
string | Record<string, string>
optional
Error message to show when the action fails (overrides the raw error).
refreshAfter
boolean
optional (default: false)
Refresh view after execution
opensInNewTab
boolean
optional
Open 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.
Accessible 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.
ariaDescribedBy
string
optional
ID of element providing additional description (WAI-ARIA aria-describedby)
role
string
optional
WAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")
[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.
fields
never
optional
[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.
targetVariable
never
optional
[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.
layout
never
optional
[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.
showSearch
never
optional
[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.
aria
never
optional
[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.
[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.
fields
never
optional
[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.
mode
never
optional
[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.
submitLabel
never
optional
[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.
onSubmit
never
optional
[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.
aria
never
optional
[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.
Accessible 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.
ariaDescribedBy
string
optional
ID of element providing additional description (WAI-ARIA aria-describedby)
role
string
optional
WAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")
Owning 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
mode
Enum<'diagram' | 'matrix' | 'summary'>
optional
Render form; defaults per type (diagram for flow/state_machine, matrix for permission)
detail
Enum<'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
Accessible 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.
ariaDescribedBy
string
optional
ID of element providing additional description (WAI-ARIA aria-describedby)
role
string
optional
WAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")
Accessible 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.
ariaDescribedBy
string
optional
ID of element providing additional description (WAI-ARIA aria-describedby)
role
string
optional
WAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")
Field whose value is written into the bound page variable (default id)
label
string | Record<string, string>
optional
Control label rendered above the select
filter
any
optional
Filter criteria for available records
sort
{ field: string; order: Enum<'asc' | 'desc'> }[]
optional
Row order — synonym of the component-level dataSource.sort, which takes precedence when both are set
limit
integer
optional
Max records offered — synonym of the component-level dataSource.limit, which takes precedence when both are set (renderer default 50)
targetVariable
never
optional
[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.
placeholder
string | Record<string, string>
optional
Placeholder text
emptyText
string | Record<string, string>
optional
Text shown when the query returns no records (default "No records")
displayField
never
optional
[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.
searchFields
never
optional
[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.
multiple
never
optional
[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.
Accessible 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.
ariaDescribedBy
string
optional
ID of element providing additional description (WAI-ARIA aria-describedby)
role
string
optional
WAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")
Native input type — drives keyboard/validation affordance and how the bound value is coerced (number → numeric).
label
string | Record<string, string>
optional
Field label shown above the input
placeholder
string | Record<string, string>
optional
Placeholder text shown when empty
defaultValue
string | number
optional
Initial value; seeds the bound page variable on mount
required
boolean
optional (default: false)
Mark the field as required
disabled
boolean
optional (default: false)
Disable the input
description
string | Record<string, string>
optional
Helper text shown below the input
targetVariable
never
optional
[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.
Accessible 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.
ariaDescribedBy
string
optional
ID of element providing additional description (WAI-ARIA aria-describedby)
role
string
optional
WAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")
Accessible 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.
ariaDescribedBy
string
optional
ID of element providing additional description (WAI-ARIA aria-describedby)
role
string
optional
WAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")
Object this grid binds to. Optional because the component-level dataSource binding can supply the object instead
label
string | Record<string, string>
optional
Grid label — used as the table caption and export file title
title
string | Record<string, string>
optional
Fallback for label (the renderer reads label || title)
columns
any[]
optional
Columns: field names or column definition objects
fields
any[]
optional
Field list fallback used when columns is absent
filter
any
optional
Base query filter (ObjectQL filter array/AST) — lowered to the wire $filter. THE key, singular — not the plural misspelling
defaultFilters
any
optional
Legacy base-filter fallback, read only when filter is absent. Prefer filter
sort
any
optional
Initial sort (array of { field, order })
defaultSort
never
optional
[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.
Data 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
staticData
any[]
optional
Deprecated bare-array static-rows shortcut the renderer still reads. Prefer data: { provider: 'value', items: [...] }
Object this metric aggregates. Optional because the component-level dataSource binding can supply the object instead
label
string | Record<string, string>
optional
Metric label
description
string | Record<string, string>
optional
Helper text under the value
title
string | Record<string, string>
optional
Drill-down panel title; defaults to the metric label
icon
string
optional
Lucide 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).
Display label — the default-language string, or an inline locale map ({ en, "zh-CN" }) resolved at render time
icon
string
optional
Lucide 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>.
Accessible 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.
ariaDescribedBy
string
optional
ID of element providing additional description (WAI-ARIA aria-describedby)
role
string
optional
WAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")
Display label — the default-language string, or an inline locale map ({ en, "zh-CN" }) resolved at render time
bordered
boolean
optional (default: true)
actions
never
optional
[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.
children
any[]
optional
Card content components, in order (the card body slot)
body
never
optional
[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.
Accessible 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.
ariaDescribedBy
string
optional
ID of element providing additional description (WAI-ARIA aria-describedby)
role
string
optional
WAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")
Page 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.
subtitle
string | Record<string, string>
optional
Page subtitle
icon
never
optional
[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.
breadcrumb
boolean
optional (default: true)
Show breadcrumb
actions
string[]
optional
Action IDs to show in header
recordChrome
boolean
optional (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.
showStar
boolean
optional (default: true)
Show the follow (favourite) star beside the record title. Part of the record chrome — no effect when recordChrome is false.
showCopyId
boolean
optional (default: true)
Show the copy-record-id button beside the record title. Part of the record chrome — no effect when recordChrome is false.
maxVisible
integer
optional
How many header actions render as inline buttons before the rest fold into the overflow menu (renderer default 3).
mobileMaxVisible
integer
optional
The maxVisible budget on mobile viewports (renderer default 1).
Accessible 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.
ariaDescribedBy
string
optional
ID of element providing additional description (WAI-ARIA aria-describedby)
role
string
optional
WAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")
Tab-strip visual style: 'line' underlines the active tab, 'card' frames each tab, 'pill' renders rounded pills
type
never
optional
[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.
position
Enum<'top' | 'left'>
optional (default: "top")
alwaysShowStrip
boolean
optional
Render the tab strip even when only one tab is visible (renderer default: a one-tab strip is hidden).
Display label — the default-language string, or an inline locale map ({ en, "zh-CN" }) resolved at render time
icon
string
optional
Lucide 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.
Visibility 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.
value
string
optional
Stable ?tab= URL token for this tab (default: index-derived tab-<i>, which is not durable across item-list changes)
count
integer
optional
Badge count shown next to the tab label (default: derived from record:related_list descendants)
Accessible 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.
ariaDescribedBy
string
optional
ID of element providing additional description (WAI-ARIA aria-describedby)
role
string
optional
WAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")
Feed 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.
Accessible 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.
ariaDescribedBy
string
optional
ID of element providing additional description (WAI-ARIA aria-describedby)
role
string
optional
WAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")
Name 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.
label
string | Record<string, string>
optional
CTA button label — a string or an inline locale map, resolved with the same pickLocalized chain as title/body (default: the action's own label).
Banner severity — styling, default icon, and the a11y role (error renders role="alert"/assertive; the rest role="status"/polite). Renderer default: info.
title
string | Record<string, string>
optional
Banner title — a string or an inline locale map ({ en, "zh-CN", … }), resolved to the current language at render (pickLocalized).
body
string | Record<string, string>
optional
Banner body — a string or an inline locale map, resolved like title.
Visibility 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.
icon
string
optional
Lucide icon name (renderer default: the severity's own icon). Read on this component — contrast the rail's refused icon, which no render path reads.
Optional call-to-action button rendered under the body — { actionName, label?, variant? }, resolved from the object's declared actions.
dismissible
boolean
optional
Render an X control; dismissal is remembered per object/record in localStorage (renderer default: off).
dismissKey
string
optional
Stable 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).
Name 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.
label
string | Record<string, string>
optional
CTA button label — a string or an inline locale map, resolved with the same pickLocalized chain as title/body (default: the action's own label).
Where 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).
width
string | number
optional
Panel width (e.g., "350px", "30%") — side positions (right/left) only.
collapsible
boolean
optional
Whether the panel can be collapsed (renderer default: off).
defaultCollapsed
boolean
optional
Whether the panel starts collapsed (renderer default: off; only meaningful with collapsible).
Feed 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.
Accessible 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.
ariaDescribedBy
string
optional
ID of element providing additional description (WAI-ARIA aria-describedby)
role
string
optional
WAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")
[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.
Field groups rendered as the detail body, in order. Object form: { name?, label?, columns?, fields, hideEmpty?, collapsible?, showBorder?, defaultCollapsed?, icon?, description?, headerColor? }.
fields
string[]
optional
Explicit field list to display (optional, overrides highlightFields)
hideFields
string[]
optional
Field 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)
inlineEdit
boolean
optional
Allow inline field editing in the detail body (renderer default: on, where the object itself is editable — set false to force it off).
showHeader
boolean
optional
Render the detail body's own heading (renderer default: off).
Stable section identifier for i18n lookup (snake_case) — resolves objects.<object>._sections.<name>.label; a nameless section renders its authored label in every locale
label
string | Record<string, string>
optional
Section heading (omit for an untitled, borderless section)
columns
integer
optional
Field-grid columns for this section (1-4). Omitted → the renderer derives the width.
fields
string[]
✅
Field names rendered in this section, in order
hideEmpty
boolean
optional
Hide 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).
collapsible
boolean
optional
Render this section as a collapsible card — the heading becomes a chevron toggle, initially expanded (renderer default: off).
showBorder
boolean
optional
Draw 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.
defaultCollapsed
boolean
optional
Start a collapsible: true section collapsed (renderer default: expanded). Consulted only when collapsible is on — a non-collapsible section never reads its collapse state.
icon
string
optional
Heading 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.
description
string
optional
Sub-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.
Section-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.
Accessible 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.
ariaDescribedBy
string
optional
ID of element providing additional description (WAI-ARIA aria-describedby)
role
string
optional
WAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")
Render 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.
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.
Render 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.
Accessible 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.
ariaDescribedBy
string
optional
ID of element providing additional description (WAI-ARIA aria-describedby)
role
string
optional
WAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")
Maximum history entries displayed, and the $top of the self-fetch query (renderer default: 50).
emptyText
string
optional
Copy 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").
unknownUserText
string
optional
Copy substituted when an entry has no resolvable actor. Literal string, every locale (renderer default: "Unknown user").
Accessible 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.
ariaDescribedBy
string
optional
ID of element providing additional description (WAI-ARIA aria-describedby)
role
string
optional
WAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")
Names 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.
requiredPermissions
string[]
optional
Hide the whole bar unless the current user holds every named permission on this object.
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.
hideEmpty
boolean
optional
Fold entries whose related count is 0 into a single "+ N empty" expander chip (renderer default: on; set false to always render every card).
Related object name whose records this card summarizes (e.g. "task", "opportunity_quote")
relationshipField
string
✅
Field on the related object that points back to this record (e.g. "account_id")
title
string
optional
Literal 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.
limit
integer
optional
Preview rows per card, and the $top of the one query this entry issues (renderer default: 3).
displayField
string
optional
Field of the related record rendered in each preview row (renderer fallback when omitted: name / title / subject / label / … / id).
Field on related object that points to this record (e.g., "account_id")
relationshipValueField
string
optional (default: "id")
Parent-record field whose value relationshipField stores (default 'id'; e.g. 'name' for name-keyed junctions).
columns
string[]
optional
Fields 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.
Filter 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.
Accessible 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.
ariaDescribedBy
string
optional
ID of element providing additional description (WAI-ARIA aria-describedby)
role
string
optional
WAI-ARIA role attribute (e.g., "dialog", "navigation", "alert")
Related object name whose records this card summarizes (e.g. "task", "opportunity_quote")
relationshipField
string
✅
Field on the related object that points back to this record (e.g. "account_id")
title
string
optional
Literal 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.
limit
integer
optional
Preview rows per card, and the $top of the one query this entry issues (renderer default: 3).
displayField
string
optional
Field of the related record rendered in each preview row (renderer fallback when omitted: name / title / subject / label / … / id).