Dynamic UI SDK

The Dynamic UI SDK is the typed authoring surface for record forms, page UI blocks, and PDF document layouts. Your code returns a tree of supported components, and the platform renderer handles the rest.

Authoring Pattern

Each UI codeblock exports run() and returns SDK.GlobalStore(...).

Prefer destructuring components from SDK and using capitalized JSX values such as Flex, Text, and CollectionTable inside the returned tree.

import { Params, ReturnType } from './data';
import { SDK } from './external';

export function run(params: Params): ReturnType {
	const { Badge, CollectionTable, Flex, Text } = SDK;

	return SDK.GlobalStore({
		data: {
			selectedStatus: 'active'
		},
		ui: (store) => (
			<Flex direction="column" gap={4}>
				<Text textStyle="h2" content="Operations overview" />
				<Badge content={store.read('data.selectedStatus')} />
				<CollectionTable collectionName="projects" title="Projects" />
			</Flex>
		)
	});
}

Store API

The store object supports four core patterns:

  1. store.bind(path)
  2. store.read(path)
  3. store.read(expr, { mode: 'CEL' })
  4. store.derive(pointer, expression)

Scoped Callbacks

When a component introduces a nested item or row scope, use the typed callback that component provides instead of manually re-resolving paths.

  • Repeater.items((item) => ...)
  • DataGrid.columns((row) => [...])
  • CollectionTable.details((row) => ...)
  • Kanban.details((row) => ...)
import { Params, ReturnType } from './data';
import { SDK } from './external';

export function run(_params: Params): ReturnType {
	const { DataGrid, Flex, FormInput, GridColumn, Repeater, Text } = SDK;

	return SDK.GlobalStore({
		data: {
			items: [{ sku: 'A-1', qty: 1 }],
			rows: [{ name: 'Ada', qty: 2 }]
		},
		ui: (store) => (
			<Flex direction="column" gap={4}>
				<Repeater
					value={store.bind('data.items')}
					items={(item) => <FormInput label="SKU" value={item.bind('sku')} />}
				/>
				<DataGrid
					value={store.bind('data.rows')}
					columns={(row) => [
						<GridColumn header="Name" cell={<FormInput label="Name" value={row.bind('name')} />} />,
						<GridColumn header="Qty" cell={<Text content={row.read('qty')} />} />
					]}
				/>
			</Flex>
		)
	});
}

CEL in Dynamic UI

Use CEL for:

  • visibility rules,
  • dynamic props,
  • derived values,
  • pre_query expressions that depend on current scope.

Validation Behavior

Dynamic UI includes meaningful validation, especially in preview and invariant-check flows. Normal runtime rendering is intentionally lighter so page and form execution stays fast.

Author against the supported contract
Write Dynamic UI using the current SDK props and supported registry components. Do not assume a custom prop model that is not in the generated types for the codeblock.
Prefer capitalized SDK components in TSX
The most readable authoring style is const { Flex, Text, FormInput } = SDK; followed by capitalized JSX component usage. This keeps examples aligned with the runtime SDK and the current type-safety tests.

Components

Dynamic UI supports a broad but controlled registry of components, including:

  • Layout and content: Flex, Text, Badge, Image, Divider, Chart
  • Form components: FormInput, FormButton, Combobox, Checkbox, CheckboxGroup
  • Structured views: Tabs, Steps, TreeView, DropdownMenu
  • Data surfaces: DataGrid, Repeater, Table, CollectionTable, TaskBlock, Kanban, Timeline
  • PDF layout: Document, Page, View

Supported Chart Types

The current chart component supports four chart kinds:

  • bar: Compare values across categories. Provide cartesian data, an `xKey`, and one or more `series`. Use `stacked` when multiple series should accumulate.
  • line: Show trends over time or ordered sequences. Provide cartesian data with an `xKey` and `series`. Use `curve` when you want linear, natural, or step rendering.
  • area: Show trend plus volume emphasis. Use the same cartesian shape as bar and line charts. This works well when totals or stacked accumulation matter visually.
  • donut: Show part-to-whole composition. Provide `data` as `{ key, value }[]` and use `innerRadius` to tune the center opening.

All chart specs also support shared metadata such as title, description, config, showLegend, showTooltip, showGrid, and valueFormat.

import { Params, ReturnType } from './data';
import { SDK } from './external';

export function run(_params: Params): ReturnType {
	const { Chart } = SDK;

	return SDK.GlobalStore({
		data: {},
		ui: () => (
			<Chart
				spec={{
					kind: 'bar',
					title: 'Projects by status',
					xKey: 'status',
					series: ['count'],
					data: [
						{ status: 'Active', count: 12 },
						{ status: 'Blocked', count: 3 },
						{ status: 'Done', count: 9 }
					],
					config: {
						count: { label: 'Projects' }
					}
				}}
			/>
		)
	});
}
Choose chart types by the decision the user needs to make
Use bar charts for comparison, line and area charts for trends, and donut charts for composition. Keep charts on page surfaces and dashboards where they support operational decisions.

Full Registry Reference

The list below covers the current authoring surface exposed by Dynamic UI, plus the one system-rendered placeholder you may encounter at runtime.

Layout and Content

ElementWhat it doesHow to use it
FlexGeneral-purpose layout container for rows, columns, spacing, and surface styling.Use it as the default wrapper for most interfaces and pages. Put child nodes inside it and control spacing with `direction`, `gap`, `align`, and `justify`.
ViewBox-like container primarily used in PDF and structured layouts.Use it when you want a bounded visual section with its own padding, border, or background, especially in document layouts.
TextRenders labels, headings, body copy, and inline values.Use `content` for the displayed value and `textStyle` for semantic styling such as `h1`, `h2`, or `body`.
BadgeDisplays a small status or label chip.Use it for state indicators, quick counts, or compact labels. Bind `content` from store values when needed.
ImageDisplays an image with basic fitting and sizing controls.Provide `src` and optional `alt`, `width`, `height`, and `objectFit` when the page or document needs visual media.
DividerAdds a visual separator between sections.Use it to break large forms or dashboard areas into clearer chunks. Adjust `margin`, `thickness`, and `lineStyle` as needed.
EmptyShows a structured empty state with title, description, and optional children.Use it when a page or panel needs a graceful “nothing here yet” state instead of a blank surface.
ChartRenders chart specs for dashboard-style data visualization.Pass a `spec` object with one of the supported chart kinds. This is best for summary pages and reporting surfaces rather than data entry forms.

Form Components

ElementWhat it doesHow to use it
FormInputRenders a collection-aware input bound to a form field.Bind `value` with `store.bind("form.field")` or `store.derive(...)`. The actual input renderer comes from the bound collection column metadata.
FormButtonTriggers submit, clear, or store-set actions in a form.Use `action="submit"` for form submission, `action="clear"` for reset behavior, or `{ set, value }` for simple UI-state actions.
ComboboxProvides searchable or multi-select option picking.Pass `options` and bind `value` when the user needs to choose from a known set rather than from collection-backed form metadata.
CheckboxCaptures a single boolean choice.Bind `value` for yes/no decisions. The `selection-card` variant works well for visually emphasized choices.
CheckboxGroupCaptures multiple selections from a fixed list.Provide `options` and bind `value` to a string array when the user may choose several values at once.

Structured and Stateful UI

ElementWhat it doesHow to use it
TabsCreates a tab container with switchable content panels.Use it to split larger forms or dashboards into clearly named sections. Pair it with `TabContent` children.
TabContentDefines one tab panel inside `Tabs`.Set `value` and `label`, then place the tab body inside it. Every child must live under a parent `Tabs` node.
StepsCreates a multi-step flow container.Use it when users should move through a staged workflow or guided sequence. Pair it with `StepContent`.
StepContentDefines one step within a `Steps` flow.Set the `label` and optional `description`, then place the step content inside it.
TreeViewDisplays hierarchical selectable nodes.Use it for org structures, category hierarchies, or nested navigation where parent-child structure matters.
DropdownMenuShows an action menu from a trigger button.Use it for contextual actions or quick command menus. Provide `items` and bind the selected action if you need to react in store state.

Data Surfaces

ElementWhat it doesHow to use it
RepeaterRepeats a template for each item in an array.Bind the array with `value={store.bind(...)}` and pass `items={(item) => ...}` so the item store is typed from the same bind path.
DataGridRenders editable, row-based tabular input inside Dynamic UI.Bind an array value, define columns with row-store callbacks, and use it for nested line items or structured repeated form data.
GridColumnDefines one column inside a `DataGrid`.Use it only as a child of `DataGrid`, setting the `header` and the cell node to render for each row.
TableDisplays presentational tabular output.Use it for read-only summary tables or PDF output when you already know the final columns and do not need collection-table behavior.
CollectionTableEmbeds a collection browsing surface directly inside Dynamic UI.Use `collectionName` and optional `pre_query`, `features`, and `details` when you want users to browse real collection records from a page.
TaskBlockEmbeds the task system in a page or Dynamic UI surface.Use it for department queues, review lists, or work-management widgets inside app pages.
KanbanDisplays an array of records as cards grouped by a dot-path `laneKey`, with optional per-card `details` like CollectionTable.Set required `laneKey` and bind `items` to the card array, or rely on scope when it is already the card array. Use `details={(row) => …}` for card content; without `details`, use dot-path `title` / `description`. Column titles match the resolved lane value (same rules as column ids).
TimelineDisplays dated or sequenced events.Use it when users need to understand order, history, or milestone progression at a glance.

PDF Layout Elements

ElementWhat it doesHow to use it
DocumentRoot container for a PDF layout.Use it only in PDF document codeblocks. It should wrap one or more `Page` nodes.
PageDefines a single PDF page.Use it under `Document` and control paper settings such as `size`, `orientation`, and `margin`.
ViewProvides an internal layout section within a PDF page.Use it under `Page` for grouped document structure, spacing, and boxed sections.

System-Rendered Element

ElementWhat it doesHow to use it
RedactedRepresents a server-resolved redaction placeholder.You do not usually author this directly. The runtime inserts it when a user cannot access the referenced data.

Form Surfaces vs Page Surfaces

Use form_for when the UI is tied to a collection-backed record form. Use a plain data store when building a page surface or PDF document that is not itself the primary mutation form.

  • Start with a small tree and expand only when the workflow clearly needs it.
  • Use collection-backed forms for actual record editing.
  • Use page UI blocks for dashboards, contextual browsing, and embedded operational components.
  • Test with the real permission model, especially where redaction is involved.