Skip to content
ONIWC
iwc 0.1.0

UI element reference

Everything inside a screen's sections, a layout slot or a component root is an element: a JSON object with a type. IWC has 45 element types. This reference is generated from the compiler's own schema (iwc/docs/schemas/ui.schema.json) and validator, and every example on these pages was compiled and rendered by IWC — the HTML shown under Output is what it produced.

An unknown type is a compile error, and so is a property that does not apply to a type: "source" does not apply to text elements (it is used by: image, video, audio, svg, icon). Form controls (text, select, checkbox, radio, textarea…) are inputs of a form — see the form input reference.

45 elements

Properties every element accepts

PropertyTypeDescription
type"container""section""box""row""column""grid""stack""spacer""divider""header""footer""nav""navbar""sidebar""main""aside""text""image""video""audio""svg""icon""placeholder""button""link""badge""card""list""table""form""review""rating""dropdown""modal""drawer""tabs""accordion""carousel""slider""chart""slot""component""phoneSignIn""search""widget"
idstringexpression (=…)
classNamestringextra CSS classes from your stylesheets (utility-framework syntax such as md:grid-cols-2 is allowed)
styleobject {name: stringnumber}CSS properties in camelCase or kebab-case, e.g. {"padding": "80px"}
responsiveobject {name: object {name: stringnumber}}per-breakpoint styles: {"mobile": {"padding": "24px"}}
statesobject
  • active: object {name: string | number} — CSS properties in camelCase or kebab-case, e.g. {"padding": "80px"}
  • focus: object {name: string | number} — CSS properties in camelCase or kebab-case, e.g. {"padding": "80px"}
  • hover: object {name: string | number} — CSS properties in camelCase or kebab-case, e.g. {"padding": "80px"}
transitionstringCSS transition, e.g. "all 200ms ease"
animationobject
  • delay: duration (500ms, 6s…) — durations look like 500ms, 30s, 5m, 1h or 7d
  • duration: duration (500ms, 6s…) — durations look like 500ms, 30s, 5m, 1h or 7d
  • name: "fade" | "fade-up" | "fade-down" | "slide-left" | "slide-right" | "zoom" | "none"
  • trigger: "load" | "visible"
visibleexpression (=…)object
ariaLabelstring
attributesobject {name: string}extra HTML attributes: data-, aria-, role, title, lang, dir, width, height, hidden, download (others are ignored)
styleSourcestringa stylesheet to load with this element
platformsarray of "web""android""ios"the platforms this is built for, e.g. ["web"]; omitted: every platform

All element properties

The complete property list of the element definition. Properties marked Only on are rejected by the compiler on other element types.

PropertyTypeDescription
action"navigate""open""close""toggle""submit""state""api""logout""scroll""share""install""notifications""sync""pay""tracking""native"share: the system share sheet (web: Web Share, else copies the link) for target (default: this page) with value as the message; install: the browser's install prompt (pwa; hidden until the app can be installed); notifications: ask for notification permission and send the push subscription to pwa.push; sync: open the list of changes waiting to sync (offline); pay: call api for a payment, open the provider's payment sheet in a native app (hosted checkout on the web) and check it with confirm; tracking: value "start"/"stop" background location (platforms.*.background.location); native: call your own Kotlin/Swift extension named by target ("Scanner.scan") with value, and post its result to apiOnly on: button, link
altstringOnly on: image, svg
animationobject
  • delay: duration (500ms, 6s…) — durations look like 500ms, 30s, 5m, 1h or 7d
  • duration: duration (500ms, 6s…) — durations look like 500ms, 30s, 5m, 1h or 7d
  • name: "fade" | "fade-up" | "fade-down" | "slide-left" | "slide-right" | "zoom" | "none"
  • trigger: "load" | "visible"
apistringthe api file to call (phoneSignIn: the auth.exchange api)Only on: button, phoneSignIn
ariaLabelstring
attributesobject {name: string}extra HTML attributes: data-, aria-, role, title, lang, dir, width, height, hidden, download (others are ignored)
authorstringOnly on: review
autofocusbooleansearch: put the cursor in the box when the screen opensOnly on: search
autoplaybooleanOnly on: video, audio, carousel, slider
bindstringtake content from data: a field of the current item, or props.x, user.x, params.x, state.store.path
bindsobject {name: string}bind attributes: {"source": "image", "target": "slug"}
cellsarray of objectOnly on: table
chartobject
  • currency: string — ISO code for format currency
  • format: "number" | "currency" | "percent" — how values are written in labels
  • height: integer
  • kind: "bar" | "line"
  • scale: number — multiply each value for display, e.g. 0.01 to show cents as currency units
  • x: string — identifiers use letters, digits and '_' and do not start with a digit
  • y: string — identifiers use letters, digits and '_' and do not start with a digit
Only on: chart
classNamestringextra CSS classes from your stylesheets (utility-framework syntax such as md:grid-cols-2 is allowed)
collapse"links""all"navbar: what folds behind the menu button on small screens (default links)
collapseAt"mobile""tablet"navbar: the breakpoint below which it folds (default mobile)
columnsinteger (1–24)string
confirmstringpay: the api that checks the payment on the server (it receives {id, provider, paymentId, signature, status}); the screen shows success only when it answers 2xx
contentstringliteral text, or an expression starting with = ("=product.name")
controlsbooleanOnly on: video, audio
currencystringISO currency for format=currency
dataobject
  • aggregate: object — summarise in the database: one record per group with its measures; sort by a group or measure name
  • as: string — identifiers use letters, digits and '_' and do not start with a digit
  • cache: duration (500ms, 6s…) — durations look like 500ms, 30s, 5m, 1h or 7d
  • columns: array of string
  • filter: object {name: string | number | boolean | null | object}
  • include: object {name: object} — related records loaded with each record, one query per include: {"category": {}} or {"reviews": {"source": "DATABASE.reviews", "on": "product"}}
  • items: array of any — inline records for STATIC sources
  • limit: integer (1–500)
  • live: boolean — re-render when the underlying records change (server push)
  • mode: "list" | "single"
  • paginate: object
  • query: object {name: string | number | boolean | null | object} — API sources: query values passed to the api (literals or {param|query|props} references)
  • refresh: duration (500ms, 6s…) — durations look like 500ms, 30s, 5m, 1h or 7d
  • required: boolean — page data: when nothing matches, the page answers 404
  • search: object
  • sort: object
  • source: string — sources are DATABASE.<schema>, API.<name>, STATIC, USER, STATE.<store>.<list> or an expression giving a list ("=product.images")
elementsarray of element
emptyelement
errorelement
fieldsobject {name: string}card mapping: title, subtitle, text, price, image, badge, linkOnly on: card
fit"cover""contain""fill""none"Only on: image, video
format"text""number""currency""percent""date""datetime""date-long""date-short""time""markdown"markdown (text elements): the value is user-written Markdown, rendered safely (no HTML passes through)
gapstring
idstringexpression (=…)
inputsarray of inputOnly on: form, search
instantbooleansearch: search again as the visitor types (debounced; the results screen is patched in place and the box keeps focus)
intervalduration (500ms, 6s…)durations look like 500ms, 30s, 5m, 1h or 7dOnly on: carousel, slider
itemelement
itemsarray of itemOnly on: accordion, list, dropdown, navbar, nav, review
labelstring
layoutobject
  • align: "start" | "center" | "end" | "stretch" | "baseline"
  • direction: "row" | "column" | "row-reverse" | "column-reverse"
  • gap: string
  • justify: "start" | "center" | "end" | "between" | "around" | "evenly"
  • wrap: boolean
loading"lazy""eager""priority"image: lazy (default) waits until it nears the screen; eager loads at once; priority also asks for it first — use it for the picture people see first (often the largest paint)Only on: image
loopbooleanOnly on: video, audio
mutationstringidentifiers use letters, digits and '_' and do not start with a digitOnly on: button, link
mutedbooleanOnly on: video, audio
namestringicon name; search: the query parameter (default q)
newTabboolean
openbooleanaccordion/details: start openOnly on: accordion, dropdown
opensOn"click""hover"dropdown/navbar: how menus open (hover falls back to click on touch screens)
placeholderstringsearch: the hint inside the boxOnly on: search
platformsarray of "web""android""ios"the platforms this is built for, e.g. ["web"]; omitted: every platform
posterstringOnly on: video
prefixstring
propsobject {name: any}Only on: component, widget
ratingnumber
ratiostringratios look like 16/9
responsiveobject {name: object {name: stringnumber}}per-breakpoint styles: {"mobile": {"padding": "24px"}}
responsiveColumnsobject {name: integer (1–24)}grid columns per breakpoint
side"left""right""top""bottom"Only on: drawer, sidebar
slotstringin a component: the prop holding child elementsOnly on: slot
sourcestringimage/video/audio/svg URL or assets pathOnly on: image, video, audio, svg, icon
statesobject
  • active: object {name: string | number} — CSS properties in camelCase or kebab-case, e.g. {"padding": "80px"}
  • focus: object {name: string | number} — CSS properties in camelCase or kebab-case, e.g. {"padding": "80px"}
  • hover: object {name: string | number} — CSS properties in camelCase or kebab-case, e.g. {"padding": "80px"}
storestringstate store for action=stateOnly on: button, link
styleobject {name: stringnumber}CSS properties in camelCase or kebab-case, e.g. {"padding": "80px"}
styleSourcestringa stylesheet to load with this element
submitobject
  • api: string — the api file the form posts to
  • className: string — CSS classes for the submit button; they replace its variant styling
  • include: array of string
  • label: string
  • streamInto: string — a streaming api ("stream": true): the id of the element the reply's text is written into as it arrives
  • success: object
Only on: form
successobjectapi buttons: what happens after a 2xx answer
  • message: string — the confirmation shown (default "Done"; none when reloading)
  • mutation: string — store.mutation to run, e.g. cart.clear
  • navigate: string — a path to go to
  • reload: boolean — re-render the screen in place, keeping scroll, focus and open dialogs
Only on: button
suffixstring
tabsarray of objectOnly on: tabs
tag"div""span""p""section""article""aside""header""footer""nav""main""figure""figcaption""ul""ol""li""dl""dt""dd""blockquote""address""time""small""strong""em""b""i""s""u""mark""cite""q""abbr""sub""sup""del""ins""code""pre""kbd""label""hgroup""h1""h2""h3""h4""h5""h6""details""summary""button"the HTML tag a container or text element renders as, e.g. "ul", "li", "article", "figure"
targetstringroute, element id, or URL
transitionstringCSS transition, e.g. "all 200ms ease"
type"container""section""box""row""column""grid""stack""spacer""divider""header""footer""nav""navbar""sidebar""main""aside""text""image""video""audio""svg""icon""placeholder""button""link""badge""card""list""table""form""review""rating""dropdown""modal""drawer""tabs""accordion""carousel""slider""chart""slot""component""phoneSignIn""search""widget"
usestringcomponent: the component file to render; widget: the widget fileOnly on: component, widget
valueanyvalue passed to a state mutation; strings starting with item. or props. are bound
variantstringtext: heading, h1-h6, subheading, paragraph, caption, label, quote, code; button: primary, secondary, ghost
varsobject {name: string}CSS custom properties set from data, per record: {"--accent": "=color", "--progress": "=concat(pct, '%')"}; your stylesheet uses var(--accent)
visibleexpression (=…)object