Surfaces (kletso.ui/v1)

The surface document, component nodes, bindings, limits and validation, and the props of all 30 built-in component types.

Document

{
  "schema": "kletso.ui/v1",
  "surfaceId": "sfc_01J8HOTEL00001",
  "root": "card1",
  "components": { "card1": { "type": "card", "props": { "title": "Shibuya Grand Hotel", "children": ["price", "b1"] } },
                  "price": { "type": "text", "props": { "text": { "path": "/hotel/priceLabel" }, "style": "title" } },
                  "b1": { "type": "button", "props": { "label": "Book" },
                          "actions": [ { "id": "book", "kind": "agent", "value": { "intent": "book", "hotelId": "h_1" }, "label": "Book Shibuya Grand" } ] } },
  "data": { "hotel": { "priceLabel": "$120 / night" } },
  "fallbackText": "Shibuya Grand Hotel, $120 per night. Book?"
}
FieldRequiredRules
schemayesexactly kletso.ui/v1
surfaceIdyessfc_ followed by letters and digits
rootyesa key of components
componentsyes1 to 500 entries; keys are ids (letters, digits, _, -; up to 64 chars)
datanoany JSON object; the target of bindings
fallbackTextyes1 to 8192 characters; rendered when the surface cannot be displayed

Component node

"b1": { "type": "button", "props": { "label": "Book" }, "actions": [ { "id": "book", "kind": "agent", "value": {} } ] }
  • type: a built-in name or a namespaced custom type (acme.productCard).
  • props: object; container types reference children by id in props.children (and items[].children for tabs and accordion, fields for forms).
  • actions: up to 200; a button must have at least one. See Actions for the six kinds.

Bindings

A prop value of the form { "path": "/hotel/priceLabel" } is a JSON pointer (RFC 6901) resolved against data. Paths under /host/ resolve against the app’s host data first. Missing targets drop the prop so the widget uses its default. Only top-level props are resolved. Props typed “string or binding” accept either.

Limits and validation

LimitValueIssue when exceeded
Components500tooManyComponents (fatal)
Depth16depthExceeded (fatal)
Size256 KBoversize (fatal)
Any string8192 charsstringTooLong (fatal)
Any array200 itemsarrayTooLong (fatal)

Other fatal issues: invalidSchema, missingRoot, cycle, missingFallback. Non-fatal (rendered with degradation): danglingChild, buttonWithoutAction, unresolvedBinding, unknownComponent, unreachableComponent. The runtime rejects fatal surfaces before they reach the app and tells the model what to fix; the SDK re-validates and never throws.

A ui.patch event can later change a surface: data is deep-merged, components entries replace by id, null removes.

Built-in types

TypeRequired propsOptional props
texttextstyle body·title·caption·code, color default·muted·success·error
markdownmarkdown
cardtitle, subtitle, children
row, columnchildrengap sm·md·lg, align start·center·end·stretch·spaceBetween, wrap
divider
imagesrc, altaspect 1:1·4:3·16:9·3:4, fit cover·contain
avatarsrc, initials (≤3), size sm·md·lg
buttonlabel + ≥1 actionvariant primary·secondary·ghost·destructive, icon, disabled
listitems[] {id, title}item subtitle, leading {image, icon}, trailing {text, badge, tone}, actions[]
tablecolumns[] {key, label, align?} (≤20), rows[] (≤50)caption
chartchartType line·bar·pie, series[] {name, data[{x, y}]}title, xLabel, yLabel, currency
carouselchildren
formid, fields[] (1–50; kinds text·email·number·select·date·toggle·textarea)title, submitLabel
inputname, kind text·email·number·date·textarea, labelplaceholder
selectname, label, options[] {value, label}multiple
confirmtitle, message, toolCallIdconfirmLabel, cancelLabel
loadinglabel, for (component type to show placeholders for), count (1–12)
errormessageretryable
badgelabeltone neutral·success·warning·error·info
linklabel, url
mapmarkers[] {id, lat, lng} (1–50)title, center, zoom, marker label/tone/actions, route[], staticImage, aspect
videosrcposter, title, durationSeconds, autoplay, captions, aspect
audiosrctitle, subtitle, durationSeconds, artwork, transcript
ratingvaluemax 1–10, count, label, interactive
stepsitems[] {id, title, status done·current·upcoming·failed}title, orientation, item subtitle, timestamp
accordionitems[] {id, title}item markdown, children, expanded
tabsitems[] {id, label, children} (1–8)initial, item icon
countdownendsAt (date-time)label, expiredLabel, tone
progressvalue 0–1label, detail, tone

URLs must be https:// (or r2:// for Kletso-hosted media). Custom types are validated against the props schema you synced.

Fixtures

hotel_card, flight_card, product_cards (custom type in a carousel), quick_replies, form, confirm, chart, catalog_all (every type), media_hub (map, countdown, video, audio, rating), trip_plan (progress, tabs, steps, accordion). Invalid fixtures cover every fatal and non-fatal issue code.

Last updated 2026-09-28 · Report an issue with this page