Playground
Paste A2UI, see it render
Messages (JSON or JSONL), a flat component list or a nested node, rendered live in any theme. Share it as a link; read the prompt a model gets.
Read as: JSONL messages · 4 messages · 1 surface
Loading the renderer…
No issues
What catalogPrompt({ extensions, lite, terse }) generates for the current catalog: the rules and every component a model may use.
text
Catalog https://ui.exponential.at/catalogs/core/v1.
Rules:
- Reply with A2UI v0.9 messages: createSurface{surfaceId, catalogId}, then updateComponents{surfaceId, components:[…]}; one component has id "root".
- A component = {id, component, …props, children?: [ids] | {componentId, path, key?}, slots?: {name: id}, on?: {event: action}, style?, visible?}. Children are ids, never inline; {componentId, path} repeats per item, key = the item field naming it.
- Include every required prop. A ~ prop may be a binding {path: "/json/pointer"} or a call {call, args}; bound values stay live. visible: false (or a binding) hides any component.
- Lay out with Stack, Grid, Card, Sidebar and List (anything longer than a screen); Box + style only for the rest. Wrap fields in Form.
- Responsive: a ^ prop also takes {base, sm?, md?, lg?, xl?} (from that breakpoint up). Style conditions, one level, narrow first: "@media (min-width: $breakpoint.md)": {…} (also max-width, min-height, max-height in px or $breakpoint.sm|md|lg|xl; orientation: portrait|landscape; hover: hover|none; prefers-reduced-motion: reduce), then ":hover", ":focus-visible", ":pressed". display: "none" hides.
- Prefer catalog components over Markdown, labels and tones over colours. Built-in copy (Cancel, Search…) is localized: leave it unset.
Components (props marked * are required, ~ accept a binding, ^ are responsive; =x is the default, else an enum defaults to its first value and a boolean to false):
Common props (no description below): name (form key), label, placeholder, disabled, checks (validation; every failure shows), validateOn, style (extra Box style), icon, size, tone, open (bind it), side, emptyText, dismissible, busy, loading, lines (truncate), width (px), height (px), value (bind it for two-way state), title, subtitle, description, meta, count, min, max, step, src, alt, multiple, pressable (fires press), durationMs (known length), firstDayOfWeek (0 = Sunday; else the locale's), direction, orientation, gap, aspectRatio (width/height), text.
Box: A styled container laid out by the whitelisted style object; the primitive every macro expands into.
children; on: press
style: style
pressable: boolean
Stack: A flex container that lays its children out in one direction with a gap.
children
direction^: horizontal|vertical="vertical"
gap^: none|xs|sm|md|lg|xl="md"
align^: start|center|end|stretch="stretch" — Cross-axis alignment of the children.
justify^: start|center|end|between|around|evenly — Main-axis distribution of the children.
wrap^: boolean — Lets children wrap onto new lines.
style: style
Grid: An equal-column grid for cards and tiles.
children
columns^: number=2 — Equal columns 1–6 (`{base: 1, md: 2, lg: 3}`).
gap^: none|xs|sm|md|lg|xl="md"
style: style
Card: A bordered content card with an optional title and description; use it for grouped content, not page headers.
children
title: string
description: string
padded: boolean=true — Pads the body; off for edge-to-edge rows.
style: style
Separator: A hairline that divides content.
orientation: horizontal|vertical
List: A windowed scrolling list; required for anything longer than a screen, children may come from a data template.
children; slots: section
direction: vertical|horizontal
gap: none|xs|sm|md|lg|xl
divided: boolean — Draws a hairline between items.
sectionBy: string — Groups consecutive template items by this field; slot `section` = each header (scope {value, count}).
stickyHeaders: boolean — Pins the current section header.
style: style
Resizable: Panels split by draggable handles; each child is one panel.
children; on: change
direction^: horizontal|vertical
sizes~: [number] — Percent per panel; bind it.
panels: [panel] — Per-panel limits, by index.
handle: boolean — Draws a grip on each handle.
style: style
ScrollArea: A scrolling region of bounded height or width.
children
direction: vertical|horizontal|both
maxHeight: number — Px it scrolls within; omit to fill the parent.
style: style
Sidebar: A two-column shell: a navigation column (`sidebar` slot) beside the children, hidden below a breakpoint or when `collapsed`; give narrow screens another way in (a `bar` Segmented, or a Drawer from an AppBar button).
children; slots: sidebar
side: left|right
width: number=240
collapseBelow: never|sm|md|lg|xl="md" — Hides the column below this breakpoint.
collapsed~: boolean — Hides the column at any width; bind it to a toggle.
AppBar: A top bar with a title, an optional subtitle and back button, and `leading`/`trailing` slots for controls.
slots: leading, trailing; on: back
title*~: string
subtitle~: string
back: boolean — Shows a back button that fires `back`.
Section: A band header over hairline-divided rows: a title with an optional caption, count and glyph, foldable, tinted; no title = just the rows.
children; slots: leading, trailing; on: change
title~: string
caption: string — Muted text after the title.
count: number
icon: icon
collapsible: boolean — The header folds the rows (chevron, press).
open~: boolean=true
tint: neutral|primary|success|warning|danger|info — The band's colour tone.
tree: boolean — The rows form a tree: each `Row.depth` indents and draws its guides.
style: style
Group: A form-field container: a rounded group of rows with an optional title and footnote.
children
title: string
footer: string — A muted note under the group.
Text: A run of text in one of the type styles; prefer dedicated components over inline markdown.
text*~: string
variant: body|caption|muted|lead|code|label|title — The type style.
align: start|center|end — Horizontal alignment inside its box.
lines: number
tone: neutral|primary|success|warning|danger|info
live: off|polite|assertive — Announces text changes to screen readers (`assertive` interrupts).
style: style
Heading: A section or page heading at one of four levels.
text*~: string
level: h1|h2|h3|h4="h2" — h1 is the page title, h4 the smallest.
Markdown: Rendered GitHub-flavoured markdown, for prose.
text*~: markdown
lines: number
style: style
CodeBlock: Source code in a mono block with built-in syntax colouring, optional line numbers and a copy button.
code*~: string — The source text.
language: plain|json|js|ts|tsx|rust|swift|kotlin|python|bash|html|css|sql|yaml|markdown — The syntax colouring.
title: string
lineNumbers: boolean — Shows a line-number gutter.
wrap: boolean — Wraps long lines instead of scrolling sideways.
copyable: boolean=true — Shows the copy-to-clipboard button.
highlight: [number] — 1-based line numbers to emphasise.
maxLines: number — Lines shown before the block scrolls.
Kbd: A keyboard shortcut drawn as a key cap.
keys*: string — The shortcut text (`⌘K`, `Ctrl+Shift+P`).
Label: A caption for a control that has no label of its own, with an optional required mark.
text*~: string
for: string — The id of the control it labels.
required: boolean — Adds the required mark.
Image: A picture from a URL, or a placeholder box when it has none.
src~: url
alt*: string
fit: contain|cover|fill|none|scaleDown="cover" — How the picture fills its box.
width: number
height: number
aspectRatio: number
fallback: icon — An icon shown when the picture fails or is missing.
loading: lazy|eager
focalX: number — Horizontal focal point 0..1 kept when cropped (0.5).
focalY: number — Vertical focal point 0..1 kept when cropped (0.5).
style: style
Icon: One icon from the shared Lucide registry, by name.
name*: icon
size: sm|default|lg="default"
tone: neutral|primary|success|warning|danger|info
label: string
Video: An inline video player with native controls.
src*~: url
poster: url — A still shown before playback.
durationMs: number
autoplay: boolean — Starts muted playback on appear.
aspectRatio: number=1.7777778
style: style
AudioPlayer: An inline audio player with a title and native controls.
src*~: url
title: string
durationMs: number
Avatar: A round user picture that falls back to initials on a stable hue.
name*~: string
src~: url
size: sm|default|lg="default"
seed: string — Hashes the fallback hue; defaults to the name.
Carousel: A horizontally paging scroller; each child is one page.
children; on: change
page~: number=0 — The active page index.
loop: boolean — Wraps from the last page to the first.
indicators: boolean=true — Shows the page dots.
Tabs: Tab navigation; the child at index i is the panel of tab i.
children; on: change
tabs*: [tab] — The tab headers in order.
value~: string
fill: boolean — Stretches the headers across the width.
Segmented: ONE row of segments selecting one or many values: the pill-track segmented control, bare toggles, joined outline buttons or a bottom bar of destinations.
on: change
items*: [option] — The segments in order.
type: single|multiple — One active value or several.
value~: string
variant: segmented|toggles|outline|bar — The segmented track, bare `toggles`, joined `outline` buttons, or a full-width `bar` with icons over labels.
size: sm|default|lg="default"
fill: boolean — Stretches the segments across the width (a `bar` always does).
Accordion: Collapsible sections; the child at index i is the body of item i.
children; on: change
items*: [accordionItem] — The section headers in order.
type: single|multiple — One section open at a time, or any number.
value~: string
Collapsible: One disclosure section with a title row that shows or hides its children.
children; on: change
title*: string
open~: boolean
count: number
Pagination: Previous, next and the current page out of a total.
on: change
totalPages*: number — How many pages there are.
page~: number=1 — The current 1-based page; bind it.
Breadcrumb: The path to the current page; every item but the last is a link that fires `select` with its value.
on: select
items*: [option] — The path from the root to the current page.
Stepper: Wizard progress: numbered steps, finished ones ticked.
steps*: [step] — The steps in order.
current~: number=0 — The 0-based index of the active step.
orientation: horizontal|vertical
Dialog: A centred modal over the surface, opened by its trigger slot or by binding `open`.
children; slots: trigger, footer; on: change
title: string
description: string
open~: boolean
dismissible: boolean=true
Drawer: A panel sliding in from an edge (a bottom sheet on phones).
children; slots: trigger, footer; on: change
title: string
description: string
open~: boolean
side^: top|right|bottom|left="bottom"
dismissible: boolean=true
dragToDismiss: boolean=true — Lets a swipe toward its edge close it.
AlertDialog: A modal that asks for a confirmation and ignores clicks outside; fires `confirm` or `cancel`.
children; slots: trigger; on: confirm, cancel, change
title*: string
description: string
confirmLabel: string="$string.confirm" — The confirming button's text.
cancelLabel: string="$string.cancel" — The cancelling button's text.
destructive: boolean — Styles the confirming button as dangerous.
open~: boolean
Popover: A small panel anchored to its trigger, opened on press.
children; slots: trigger; on: change
open~: boolean
side: top|right|bottom|left="bottom"
openOn: press|hover — Press, or hover over the trigger (press on touch).
Tooltip: A short hint shown on hover or long-press over its children.
children
content*: string — The hint text.
side: top|right|bottom|left
Menu: A menu of actions, checkboxes, groups and one-level submenus: opened by pressing its child (or a default button) or by right-click / long-press on it.
one child; on: select
label: string
icon: icon
items*: [menuItem] — The entries in order.
openOn: press|contextmenu — A press on the child, or the context gesture over it.
Toast: A transient notice in the toast layer; render one per notice with `open` bound.
on: dismiss, action, change
title*~: string
description~: string
type: info|success|warning|error — The severity, picking icon and tone (`error` interrupts screen readers).
open~: boolean=true
duration: number=5000 — Ms until it dismisses itself; 0 = never.
actionLabel: string — A button label; pressing it fires `action`.
dismissible: boolean=true
Badge: A small count or status label.
text*~: string
variant: default|secondary|outline|ghost|destructive|link — Filled, secondary, outlined or destructive.
icon: icon
Alert: An inline banner with an icon, a title and a message.
title*: string
message: string — The detail under the heading.
type: info|success|warning|error — The severity, which picks the icon and tone.
Chip: A small labelled token: a pill for a filter, label or state, or a rect naming an entity with a glyph or picture, optionally removable.
slots: leading; on: press, remove
label*~: string
shape: pill|rect — A rounded pill or a squarer entity chip.
selected: boolean — Draws it as the active choice.
tone: neutral|primary|success|warning|danger|info
dot: color — A colour dot before the text (a label chip).
icon: icon
image: url — A round picture instead of the icon.
detail: string — Muted text after the label.
removable: boolean — Shows a remove control that fires `remove`.
pressable: boolean
EmptyState: A centred icon, title and explanation for an empty list, with an optional action.
on: press
icon*: icon
title*: string
description: string
actionLabel: string — A button label; pressing it fires `press`.
Progress: A horizontal progress bar with an optional label.
value*~: number
max: number=100
label: string
tone: neutral|primary|success|warning|danger|info="primary"
Meter: A usage track: a bar of coloured segments against a maximum, with a caption and a value.
segments*: [segment] — The slices in order.
max: number=100
label: string
value: string
Ring: A circular progress ring for a fraction, sized like an icon.
value*~: number
size: sm|default|lg="default"
tone: neutral|primary|success|warning|danger|info="primary"
label: string
Spinner: An indeterminate activity indicator.
size: sm|default|lg="default"
label: string
Skeleton: A shimmering placeholder block while content loads.
width: string
height: string
rounded: boolean — A circle instead of a bar.
Table: A data table of typed columns over rows: sorting, row selection, widths, alignment, windowed; a `slot` column renders a component per cell.
slots: *; on: sort, select, rowPress
columns*: [column] — The columns in order.
rows*~: [object] — One object per row keyed by column key; bind it for live data.
rowKey: string="id" — The row field that identifies a row.
sort~: sort — The active sort; bound = you order `rows`, unbound = sorted locally.
selectable: none|single|multiple — Row selection (many = a checkbox column).
selected~: [string] — The selected row keys; bind them.
caption: string — A caption under the table.
emptyText: string="$string.noResults"
striped: boolean — Alternates row fills.
density: default|compact — Row height class.
stickyHeader: boolean — Keeps the header visible while the rows scroll.
Chart: A bar, stacked-bar, line, area, pie, donut or sparkline chart with axes, legend and tooltip, as wide as its box.
kind*: bar|stackedBar|line|area|pie|donut|sparkline — The chart form.
categories~: [string] — The x-axis labels, or the pie slices; omit for a sparkline.
series*~: [series] — One per line, bar group or pie ring; coloured $color.chart1..8 unless toned.
title: string
height: number=200
xLabel: string — A caption under the x axis.
yLabel: string — A caption beside the y axis.
min: number
max: number
showAxes: boolean=true — Draws the axes with tick labels.
showGrid: boolean=true — Draws horizontal grid lines at the ticks.
showLegend: boolean=true — Draws the legend (2+ series or slices).
showValues: boolean — Writes each value on its bar, point or slice.
Sparkline: A tiny inline trend line of recent values, no axes or legend.
values*~: [number] — The points, oldest first.
tone: neutral|primary|success|warning|danger|info="primary"
height: number=24
Button: A press target with a label and optional icon (or one custom child).
one child; on: press
label~: string
icon: icon
variant: default|secondary|outline|ghost|destructive|link — `default` = the primary action, `destructive` = dangerous, `ghost`/`link` = quiet.
size: sm|default|lg|icon="default"
disabled~: boolean
loading: boolean
submit: boolean — Submits the enclosing Form on press.
Link: Inline link text that opens a URL or fires `press`.
on: press
label*~: string
href: url — The URL to open; omit to handle `press` yourself.
external: boolean — Marks it as leaving the app.
Toggle: A two-state button that stays pressed.
on: change
label*: string
icon: icon
pressed~: boolean — The state; bind it.
variant: default|outline — Plain or outlined.
size: sm|default|lg="default"
Form: Collects its fields by `name` and fires `submit` with their values once every check passes (a `submit` Button or Enter submits).
children; on: submit, invalid, change
name*: string
disabled~: boolean
busy~: boolean
summary: boolean — Also lists every failed check above the fields.
Input: A single-line text field.
on: change, submit, focus, blur
label*: string
name*: string
type: text|email|password|number|search|url|tel — The keyboard and masking kind.
placeholder: string
value~: string
disabled: boolean
checks: [check]
validateOn: change|blur|submit="blur"
Textarea: A multi-line text field.
on: change, focus, blur
label*: string
name*: string
placeholder: string
rows: number=3 — Visible lines (the minimum when autosizing).
autosize: boolean — Grows with the text from `rows` up to `maxRows`.
maxRows: number — Autosize stops growing here and scrolls.
value~: string
disabled: boolean
checks: [check]
validateOn: change|blur|submit="blur"
NumberField: A numeric field with steppers, min/max/step clamping and locale formatting.
on: change, submit, focus, blur
label*: string
name*: string
value~: number
min: number
max: number
step: number=1
precision: number — Decimal places shown; defaults to the step's.
unit: string — A suffix after the number (`kg`, `%`).
placeholder: string
disabled: boolean
checks: [check]
validateOn: change|blur|submit="blur"
Checkbox: A labelled checkbox; bind `checked`.
on: change
label*~: string
name*: string
checked~: boolean — The state; bind it.
disabled: boolean
checks: [check]
Radio: A labelled group of radio options choosing one value; bind `value`.
on: change
label: string
name*: string
options*: [option] — The choices in order.
value~: string
orientation: horizontal|vertical="vertical"
checks: [check]
Switch: A labelled on/off switch; bind `checked`.
on: change
label*~: string
name*: string
checked~: boolean — The state; bind it.
description: string
disabled: boolean
Slider: A range slider between min and max; bind `value`.
on: change
label: string
min: number=0
max*: number
step: number=1
value~: number
Rating: A row of stars scoring out of `max`; `readOnly` only displays.
on: change
value~: number=0
max: number=5
readOnly: boolean — Display only; no presses.
size: sm|default|lg="default"
Select: A dropdown picker of one or many options; `searchable` makes it a filtering combobox, `source` a host list.
on: change, search
label: string
name*: string
options~: [option] — Inline choices, or a path the host refills on `search`; omit with `source`.
source: string — A host list id (e.g. `exp:statuses`) that supplies the options.
placeholder: string
value~: string
multiple: boolean
searchable: boolean — Adds a filter field; typing fires `search`.
emptyText: string="$string.noResults"
disabled: boolean
checks: [check]
validateOn: change|blur|submit
ChipInput: A multi-value field of removable chips (Enter or comma adds); bind `values`.
on: change, add, remove
label: string
name*: string
values~: [string] — The entries; bind them.
suggestions~: [option] — Completions offered while typing.
placeholder: string
max: number
disabled: boolean
checks: [check]
DatePicker: A calendar date field (ISO yyyy-mm-dd).
on: change
label: string
name*: string
value~: date
min: date
max: date
placeholder: string
firstDayOfWeek: number
DateRangePicker: A two-date range field with one calendar (ISO dates).
on: change
label: string
name*: string
start~: date — The first day as yyyy-mm-dd, or empty.
end~: date — The last day as yyyy-mm-dd, or empty.
min: date
max: date
placeholder: string
firstDayOfWeek: number
TimePicker: A time-of-day field (`HH:mm`) picked from a list every `step` minutes, or typed.
on: change
label: string
name*: string
value~: string
min: string
max: string
step: number=15
placeholder: string
disabled: boolean
FileUpload: A drop zone with a browse button; files reach the host via `upload`, which lists them back in `files`.
on: upload, remove
label: string
name*: string
accept: string — Accepted types, comma-separated (`image/*,.pdf`).
multiple: boolean
maxSize: number — Max bytes per file; bigger ones are refused.
files~: [file] — The attached files, each removable.
hint: string — Text under the drop zone's title.
disabled: boolean
Composer: The chat input box: a growing text field with a submit button and optional attachments.
on: submit, change, stop
placeholder: string
value~: string
submitLabel: string="$string.send" — The submit button's accessibility label.
attachments: boolean — Shows the attach control.
busy: boolean
Row: THE list row: a lead glyph or slot, a mono identifier, a title with a subtitle, trailing meta or a readable value, a slot and a chevron; flat or a card, nestable by depth.
slots: leading, trailing; on: press
title*~: string
identifier~: string — A mono identifier before the title (`EXP-12`).
subtitle~: string
meta~: string
value~: string
placeholder: string
icon: icon
chevron: none|right|selector — A trailing disclosure (`right`) or picker (`selector`) glyph.
selected: boolean — Draws it as the active row.
density: default|compact — Row height class.
surface: flat|card — A flat row, or a padded card with its own fill and border.
pressable: boolean
depth: number=0 — Nesting depth under a tree Section (0 = root); the guides are computed from the rows around it.
Shapes: option = {label*: string, value*: string, icon: icon, disabled: boolean}; check = {condition*: boolean, message*: string}; tab = {label*: string, value*: string, icon: icon, count: number}; menuItem = {label: string, value: string, kind: item|checkbox|separator|label|submenu, icon: icon, shortcut: string, checked: boolean, destructive: boolean, disabled: boolean, items: [menuItem]}; accordionItem = {title*: string, value*: string, count: number}; segment = {value*: number, tone: neutral|primary|success|warning|danger|info, label: string}; series = {name*: string, values*: [number], tone: neutral|primary|success|warning|danger|info}; step = {label*: string, description: string}; column = {key*: string, label*: string, type: text|number|date|boolean|badge|slot|currency|percent|relativeTime, slot: string, width: number, align: start|center|end, sortable: boolean, currency: string, decimals: number}; sort = {key*: string, direction*: asc|desc}; panel = {min: number, max: number, collapsible: boolean}; file = {name*: string, size: number, type: string, url: url}
Functions (client-side, the A2UI basic ones plus core ones): required, regex, length, numeric, email, formatString, formatNumber, formatCurrency, formatDate, pluralize, openUrl, and, or, not, percent, add, sub, eq, lt, clamp, cond, fallback, concat, coalesce, text, map, len, fill, set, formatPercent, formatRelativeTime.
Style keys (Box): display, flex*, justifyContent, align*, gap, width, height, min/max sizes, aspectRatio, position (relative|absolute|sticky), top/right/bottom/left, inset*, padding*/margin* (+Horizontal/Vertical/InlineStart/End), grid*, overflow(X/Y), direction, backgroundColor, backgroundGradient {angle, stops}, backdropBlur $blur.*, color, border*, opacity, boxShadow, font*, letterSpacing, text*, transition $motion.*, transform (translate/scale/rotate, paint only), animation (pulse|spin|fade-in|slide-in-up/down/left/right|shimmer), visibility, pointerEvents, userSelect, cursor. Values: px, "N%", "auto", or tokens $spacing.md, $color.primary, $radius.lg, $control.row.