Widget reference
This page is a reference: every widget a document can contain, with its properties as the contract describes them. Contract version: 9.28.0.
Who needs it: someone who reads or writes document JSON by hand, checks what a field of a published document means, or writes a renderer. To put screens into an app you do not need to read it — start with the quickstart for Flutter or React.
How to read it:
- Widgets are grouped as in the builder’s palette. Each has a table of its
props: the type of the value, whether it is required, the default, and what it means. - How a style is read — the rules of
style, which is the same on every widget. - Shared types — the types the tables link to: tokens, conditions, bindings, actions.
- The descriptions are those of the schema file
screen-schema.json, generated with it. Names in «…» are fields and blocks of that file.
Sections: Layout · Content · Actions · Progress and status · How a style is read · Shared types.
A document is a tree of nodes. Every node has the same outer shape; what differs is type and the props that go with it.
| Node field | Meaning |
|---|---|
id |
Unique within a screen, not within the document: two screens may hold copies of one composition. Address a node as screen + id. |
type |
The widget name, one of the headings below. |
props |
The properties of that widget — the tables on this page. |
children |
Child nodes, for widgets that hold other widgets. |
visibleIf |
Optional condition on data; when it does not hold, the node is not drawn. See VisibilityCondition. |
style |
Optional. The whole look of the node's box — padding, size, background, border, radius, shadow, opacity, color, text style — the same on every widget. See NodeStyle and How a style is read. |
styleWhen |
Optional list of “condition → style”. The first case whose condition holds is laid over style, field by field at the top level. See StyleCase. |
fill |
Only inside Stack: the layer takes the size of the stack. |
weight |
Only inside a non-scrolling, non-wrapping Row: the share of the row width. See NodeWeight. |
layer |
Only on a direct child of Stack: the layer becomes an overlay with its own alignment, shift and rotation, and never changes the size of the stack. See NodeLayer. |
pull |
Only where children follow one another (Screen, Column, Container, a non-scrolling, non-wrapping Row): the node and everything after it move towards the start of the main axis, over what precedes them. See NodePull. |
What a renderer does with a widget, operator or field it does not know is decided by the compatibility policy, not by the renderer.
Layout#
Screen#
Screen root: background and outer padding. Created together with the screen.
Since contract 1.0.0. Children: AppBar, Column, Row, Container, Grid, Stack, Tabs, Accordion, ChoiceGroup, Repeater, Spacer, Divider, Text, Image, Icon, Button, IconButton, ListTile, ProgressBar, CircularProgress, Badge, TextField, Switch, Checkbox, NavBar, at most 20. Extra node fields: styleOn, propsOn.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
gap |
SpacingRef | yes | "sm" |
|
align |
AlignToken | no | Where the children of the screen root that do not stretch stand across the screen (a node with its own «style.width» and the widgets of «x-style.layout.column.naturalWidth»): «start» — the start of the script (the right edge in RTL), «center», «end». Stretched children keep the full width. No field — «start», the screen as it was before 9.15.0. It is the cross alignment of the root column («x-style.layout.column.naturalWidthAlign»), so a pinned block of natural width follows it too; the app bar and the navigation bar always take the full width. | |
justify |
"start" | "center" | "end" | "between" |
no | How the children of the BODY are placed from top to bottom when the content is shorter than the visible body (the area between the app bar and the bottom zone): «start», «center», «end», «between». Content taller than the body scrolls as before and the field changes nothing. Only the children of the body take part: the app bar, the pinned block and the navigation bar do not. No field — «start». Rules — «x-style.layout.alignment.screen». | |
contentMaxWidth |
integer 320–1920 | no | The largest width of the CONTENT of the screen, in logical pixels (9.18.0). The background of the root and of the zones (app bar, bottom zone) runs edge to edge; the content of the app bar, of the body and of the bottom zone is a column no wider than this number, centred — the same in LTR and RTL. A screen narrower than the number is not changed. No field — the content takes the full width, as before 9.18.0. Rules — «x-style.layout.widthClass.contentMaxWidth». A renderer older than 9.18.0 skips the field. | |
bodyTop |
"screenTop" |
no | Where the BODY area of the screen starts (9.19.0). Without the field — at the bottom edge of the app bar (without an app bar — below the top safe inset): the screen as it was before 9.19.0. «screenTop» — at the top edge of the screen: the body lies UNDER the app bar and under the status bar, the app bar stays fixed in its place OVER the body and takes the presses in its box, and scrolled content shows through an app bar without a background. Nothing else changes: only the body scrolls. Rules — «x-style.layout.bodyTop» and «x-style.layout.safeTop». No field or an unknown word — the screen as before 9.19.0. A renderer older than 9.19.0 skips the field and draws the app bar as a strip above the body. |
AppBar#
Top bar of the screen: title, subtitle, a back button and up to two actions on the right. One only, and first.
Since contract 6.0.0. Children: IconButton, Button, at most 3. Extra node fields: pin, showOn, styleOn, motion, pressFeedback, styleScrolled.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
title |
BindableString | yes | ||
subtitle |
BindableString | no | ||
showBack |
boolean | yes | true |
|
titleAlign |
"start" | "center" |
no | Where the title block stands (9.16.0): «center» — in the centre of the bar while it fits (the rule of 9.9.0), «start» — right after the leading zone, lines aligned to the start; logical, mirrored in right-to-left scripts. Rules — «x-style.layout.appBarTitle». No field — «center», exactly as before 9.16.0. | |
titleShown |
"scrolled" |
no | When the title block is drawn (9.21.0). «scrolled» — only while the body is scrolled («x-style.layout.appBarScrolled»); at rest it is not drawn but keeps its place, so the zones do not jump. No field or an unknown word — always, exactly as before 9.21.0. |
Column#
Holds other widgets and stacks them top to bottom with an even gap.
Since contract 1.0.0. Children: Column, Row, Container, Grid, Stack, Tabs, Accordion, ChoiceGroup, Repeater, Spacer, Divider, Text, Image, Icon, Button, IconButton, ListTile, ProgressBar, CircularProgress, Badge, TextField, Switch, Checkbox, at most 30. Extra node fields: pin, showOn, styleOn, motion, pressFeedback, propsOn.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
gap |
SpacingRef | yes | "sm" |
|
align |
AlignToken | yes | "start" |
|
justify |
"start" | "center" | "end" | "between" |
no | How the children are placed along the MAIN axis (top to bottom) when the node is taller than its content: «start» — at the top, «center», «end» — at the bottom, «between» — the free space goes between the children. Free space exists only when the height of the node is named («style.height», «style.minHeight») or given by the parent (a layer with «fill»); a node as tall as its content has none, and the field changes nothing — it is not an error. «gap» stays the smallest distance between children. No field — «start». Rules — «x-style.layout.alignment». A renderer older than 9.15.0 skips the field. | |
action |
PressAction | no | ||
label |
PressLabel | no | ||
longPress |
LongPressAction | no | ||
longPressLabel |
LongPressLabel | no |
Row#
Holds other widgets and lays them left to right, with or without wrapping.
Since contract 2.0.0. Children: Column, Row, Container, Stack, Spacer, Divider, Text, Image, Icon, Button, IconButton, ListTile, ProgressBar, CircularProgress, Badge, TextField, Switch, Checkbox, at most 10. Extra node fields: pin, showOn, styleOn, motion, pressFeedback, propsOn.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
gap |
SpacingRef | yes | "sm" |
|
align |
AlignToken | yes | "center" |
|
justify |
"start" | "center" | "end" | "between" |
yes | "start" |
|
wrap |
boolean | yes | false |
|
scrollable |
boolean | no | false |
The row scrolls sideways and the children keep their natural width. Stronger than «wrap»: if both are true, the row scrolls instead of wrapping. |
carousel |
Carousel | no | Turns the sideways scroll into a carousel: the scroll snaps to the cards and dots show the position. Rules — «x-style.layout.carousel». A renderer older than 9.11.0 skips the field and shows the plain row. | |
action |
PressAction | no | ||
label |
PressLabel | no | ||
longPress |
LongPressAction | no | ||
longPressLabel |
LongPressLabel | no |
Container#
Card: holds other widgets, adding background, corner radius, shadow and padding.
Since contract 2.0.0. Children: Column, Row, Container, Grid, Stack, Tabs, Accordion, ChoiceGroup, Repeater, Spacer, Divider, Text, Image, Icon, Button, IconButton, ListTile, ProgressBar, CircularProgress, Badge, TextField, Switch, Checkbox, at most 15. Extra node fields: pin, showOn, styleOn, motion, pressFeedback, propsOn.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
direction |
ContainerDirection | no | "column" |
The direction the container stacks children in: «column» — one under another, «row» — side by side. The cross axis is the same as in the «Column» and «Row» widgets: in a column the child takes the full width of the container, in a row the children are centred vertically. Documents before 8.1.0 have no such field — there it reads «column». |
gap |
SpacingRef | yes | "none" |
|
align |
AlignToken | no | The CROSS axis. In a column container — where the children that do not stretch stand horizontally (a node with its own «style.width» and the widgets of «x-style.layout.column.naturalWidth»; stretched children keep the full width); no field — «start». In a row container — how the children stand vertically; no field — «center». Both are the container as it was before 9.15.0 («x-style.layout.alignment.cross»). | |
justify |
"start" | "center" | "end" | "between" |
no | The MAIN axis: «start», «center», «end», «between» — where the free space along the direction of the container goes. In a row container the free space is the width the children leave. In a column container it exists only when the height of the node is named («style.height», «style.minHeight») or given by the parent (a layer with «fill»); otherwise the field changes nothing and is not an error. No field — «start». Rules — «x-style.layout.alignment». | |
action |
PressAction | no | ||
label |
PressLabel | no | ||
longPress |
LongPressAction | no | ||
longPressLabel |
LongPressLabel | no |
Grid#
Holds other widgets and lays them out in equal columns, wrapping to the next row.
Since contract 8.5.0. Children: Column, Row, Container, Spacer, Stack, Text, Image, Icon, Button, IconButton, ListTile, ProgressBar, CircularProgress, Badge, at most 24. Extra node fields: pin, showOn, styleOn, motion, pressFeedback, propsOn.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
columns |
integer 2–4 | yes | 2 |
How many cells go in a row. The cell width is the same across the grid: (grid width − gaps) ÷ number of columns. |
gap |
SpacingRef | yes | "sm" |
Stack#
Layers content one on top of another: a lock on a card, a badge in the corner. First in the list is the lowest.
Since contract 8.6.0. Children: Column, Row, Container, Grid, Text, Image, Icon, Button, IconButton, ListTile, ProgressBar, CircularProgress, Badge, at most 5. Extra node fields: pin, showOn, styleOn, motion, pressFeedback.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
alignHorizontal |
AlignToken | yes | "center" |
Where a layer narrower than the stack sits: «start» — at the start of the line (on the left in LTR), «end» — at the end. |
alignVertical |
AlignToken | yes | "center" |
Where a layer shorter than the stack sits: «start» — at the top, «end» — at the bottom. |
action |
PressAction | no | ||
label |
PressLabel | no | ||
longPress |
LongPressAction | no | ||
longPressLabel |
LongPressLabel | no |
Tabs#
Several panels under one bar of titles; exactly one is visible. The user switches them.
Since contract 8.8.0. Children: Tab, at most 5. Extra node fields: pin, showOn, styleOn, motion, pressFeedback.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
initialTab |
integer 0–9007199254740991 | yes | 0 |
Index of the tab open when the screen is shown; counting from zero among ALL «Tab» children in document order — tabs hidden by «visibleIf» are counted too, so the index does not shift with data. If the named tab is hidden at that moment, the first visible tab is opened. After that the user switches tabs, and the document never learns about it. |
Tab#
One tab panel together with its title in the bar. Does not exist outside Tabs.
Since contract 8.8.0. Children: Column, Row, Container, Grid, Stack, Accordion, ChoiceGroup, Repeater, Spacer, Divider, Text, Image, Icon, Button, IconButton, ListTile, ProgressBar, CircularProgress, Badge, TextField, Switch, Checkbox, at most 15. Extra node fields: pin, showOn, styleOn, motion, pressFeedback.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
title |
BindableString | yes |
Accordion#
Holds other widgets under a title and hides them until tapped open.
Since contract 3.0.0. Children: Column, Row, Spacer, Divider, Text, Image, Icon, Button, IconButton, ListTile, at most 10. Extra node fields: pin, showOn, styleOn, motion, pressFeedback.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
title |
BindableString | yes | ||
initiallyExpanded |
boolean | yes | false |
Repeater#
Draws its single child once per record in the data. Fields of the current record are available inside.
Since contract 8.4.0. Children: Column, Row, Container, Grid, Stack, Accordion, Repeater, Spacer, Divider, Text, Image, Icon, Button, IconButton, ListTile, ProgressBar, CircularProgress, Badge, at most 2. Extra node fields: pin, showOn, styleOn, motion, pressFeedback, propsOn.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
source |
non-empty string | yes | Name of a collection from the data contract, for example «tasks». An item of that collection becomes available to the nodes inside the template under its own prefix: the «tasks» collection gives «task.title», «task.progress» and the rest of the task fields. | |
item |
non-empty string | yes | ||
direction |
ContainerDirection | no | "column" |
|
gap |
SpacingRef | yes | "sm" |
|
columns |
integer 2–4 | no | How many copies of the template go in a row. No field — one per row. The cell width is computed exactly as in Grid: (width − gaps) ÷ columns. | |
limit |
integer 1–50 | no | ||
carousel |
Carousel | no | Turns the sideways scroll into a carousel: the scroll snaps to the cards and dots show the position. Rules — «x-style.layout.carousel». A renderer older than 9.11.0 skips the field and shows the plain row. | |
where |
ListWhereCondition | no | Draw only the records for which this condition holds (9.23.0), judged in the scope of THAT record over the outer scope. A record that does not pass does not exist for the layout: the grid packs, the carousel counts stops and dots of the cards drawn, numbers count the records drawn; «limit» takes the first records that passed. A comparison by «valuePath» with no value under it holds for every record («All»). No field — every record. Rules — «x-listFilter». | |
groupBy |
non-empty string | no | Group the drawn records (9.26.0): records that follow one another with the same value under this path of the RECORD (for example «activity.day») form one group, and the SECOND child of the Repeater — the group header — is drawn before each group in the scope of its FIRST record. The order is the order of the data; groups are formed after «where» and «limit». Only a list in a column: with «columns» or a row direction the field is not published. No field — no groups, and the Repeater has one child. Rules — «x-repeaterGroup». |
Spacer#
Empty space of a given size between neighbours.
Since contract 1.0.0. Holds no children. Extra node fields: pin, showOn, styleOn, motion, pressFeedback.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
size |
SpacingRef | yes | "md" |
|
orientation |
Orientation | yes | "horizontal" |
Divider#
A thin line between neighbours.
Since contract 1.0.0. Holds no children. Extra node fields: pin, showOn, styleOn, motion, pressFeedback.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
color |
ColorRef | yes | "border" |
|
spacing |
SpacingRef | yes | "sm" |
|
orientation |
Orientation | yes | "horizontal" |
Content#
Text#
Text: a literal or a value from data. Can limit the number of lines.
Since contract 1.0.0. Holds no children. Extra node fields: pin, showOn, styleOn, motion, pressFeedback.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
content |
BindableString | yes | ||
align |
AlignToken | yes | "start" |
|
maxLines |
integer 1–20 | no | ||
overflow |
"clip" | "ellipsis" | "visible" |
yes | "ellipsis" |
|
spans |
object | no | Own styles of parts of the text, keyed by the NAME of a template value of content. Every piece of the rendered string that comes from the place {name} is drawn with this style over the style of the node. |
|
marker |
TextMarker | no | List item marker before the text (9.17.0): «bullet» — «•» in the font of the text, «number» — the number of the item among consecutive numbered siblings and a dot, «none» or no field — plain text. The text hangs: its second line starts under the first line of the text, not under the marker («x-style.layout.listMarker»). | |
animateChanges |
true |
no | When the DATA change the value of this node while it is shown, the renderer leads from the old value to the new one (9.21.0): a number of a text with a numeric format counts through the values between, a scale grows. Duration, curve, steps and when there is no transition — «x-valueTransition». No field — the value changes at once, exactly as before 9.21.0. | |
animateIn |
true |
no | When the node is SHOWN, its value grows from zero to its own (9.24.0): a number of a text with a numeric format counts up from 0 with the same curve, duration and steps as «animateChanges»; a ProgressBar or CircularProgress fills from empty. Shown — the first show of the screen, a screen shown again («back»), a node that appears (condition, width class, a new record). Rules — «x-valueAppear». No field — the value is there at once, exactly as before 9.24.0. |
Image#
A picture: an asset bundled with the app or an https link.
Since contract 1.0.0. Holds no children. Extra node fields: pin, showOn, styleOn, motion, pressFeedback.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
source |
ImageSource | yes | {"kind":"asset","asset":"placeholder"} |
|
aspectRatio |
ImageRatio | yes | "16:9" |
|
fit |
"cover" | "contain" |
no | "cover" |
|
alt |
AltText | no |
Icon#
An icon from the contract dictionary, in a given color and size.
Since contract 2.0.0. Holds no children. Extra node fields: pin, showOn, styleOn, motion, pressFeedback.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
name |
IconToken | yes | "star" |
|
iconPath |
IconPath | no | ||
size |
"sm" | "md" | "lg" |
yes | "md" |
|
glyphSize |
integer 8–128 | no | Own size of the drawing, a whole number of logical pixels (9.16.0): the side of the square the icon is drawn in. Stronger than the word in «size» and than «style.typography»; the word stays in the document as the value a renderer older than 9.16 draws. Rules — «x-style.layout.ownGlyphSize». No field — the size is the word in «size», exactly as before 9.16.0. | |
alt |
AltText | no |
Actions#
ChoiceGroup#
Holds list rows of which exactly one can be picked. The choice belongs to the group.
Since contract 6.0.0. Children: ListTile, Divider, at most 20. Extra node fields: pin, showOn, styleOn, motion, pressFeedback.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
value |
BindableString64 | yes | ||
gap |
SpacingRef | yes | "none" |
|
required |
true |
no | Must be filled before a «requiresFilled» control of the screen is enabled («x-style.layout.form.required»). No field — not required. |
Button#
A button with a label and an action: go to a screen, submit, share.
Since contract 1.0.0. Holds no children. Extra node fields: pin, showOn, styleOn, motion, pressFeedback, zone.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
label |
BindableString | yes | ||
variant |
"primary" | "secondary" | "ghost" |
yes | "primary" |
|
action |
ButtonAction | yes | {"type":"none"} |
|
fullWidth |
boolean | yes | true |
|
icon |
IconToken | no | Icon beside the label. Drawn by the rule «x-style.layout.iconBesideText»: same color as the label, a gap between them, centred on the line of the label. No field — no icon. | |
iconPath |
IconPath | no | ||
iconPosition |
IconPosition | no | ||
size |
ButtonSize | no | ||
requiresFilled |
true |
no | Disabled while a required field of the screen is not filled («x-style.layout.form.filled», «…form.button»). No field — not read. | |
disabledIf |
VisibilityCondition | no | Disabled while the condition holds; with «requiresFilled» — when either holds («x-style.layout.form.button»). No field — not disabled. | |
confirm |
"swipe" |
no | How the press is confirmed (9.22.0). «swipe» — the button is drawn as a track with a thumb at the inline start; the action and its «track» run only when the thumb is dragged to the inline end past the threshold and released; released earlier, it returns. From the keyboard and for assistive technology it is an ordinary button named by its label: Enter and Space act at once. A disabled button does not move. Rules — «x-swipeConfirm». No field or an unknown word — an ordinary press, exactly as before 9.22.0. |
IconButton#
A round button with an icon and no visible text: back, info, close. It needs a name for screen readers.
Since contract 9.5.0. Holds no children. Extra node fields: pin, showOn, styleOn, motion, pressFeedback, zone.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
icon |
IconToken | yes | "info" |
|
iconPath |
IconPath | no | ||
label |
BindableString | yes | ||
variant |
"primary" | "secondary" | "ghost" |
yes | "secondary" |
|
size |
ButtonSize | yes | "md" |
|
glyphSize |
integer 8–128 | no | Own size of the drawing, a whole number of logical pixels (9.16.0): the side of the square the icon is drawn in. Stronger than the word in «size» and than «style.typography»; the word stays in the document as the value a renderer older than 9.16 draws. Rules — «x-style.layout.ownGlyphSize». No field — the size is the word in «size», exactly as before 9.16.0. | |
action |
ButtonAction | yes | {"type":"none"} |
|
requiresFilled |
true |
no | Disabled while a required field of the screen is not filled («x-style.layout.form.filled», «…form.button»). No field — not read. | |
disabledIf |
VisibilityCondition | no | Disabled while the condition holds; with «requiresFilled» — when either holds («x-style.layout.form.button»). No field — not disabled. |
NavBar#
The bottom bar that switches sections of the app: 2–5 items, an icon above a label. It stays at the bottom while the screen scrolls.
Since contract 9.12.0. Children: NavItem, at most 5. Extra node fields: pin, showOn, styleOn, motion, pressFeedback.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
widePlacement |
"top" | "bottom" |
no | Where the bar stands when the box of the screen is «medium» or «expanded» wide (9.18.0): «top» — at the top, its items inside the app bar of the screen or, without one, in a bar of their own; «bottom» — at the bottom on every width, as on a phone. On «compact» the bar is always at the bottom. The document does not change: the bar stays the last child of the screen root. Rules — «x-style.layout.wideNav». No field — «top». | |
float |
true |
no | The bar floats over the body (9.22.0): the body area reaches the bottom of the screen and the content scrolls UNDER the bottom zone; the renderer adds the height of the zone at the end of the body content, so the last row scrolls clear of it, and puts the bottom safe inset OUTSIDE the box of the bar. The look of the pill is the style of the node (margin, radius, «backdropBlur», shadow). Read only where the bar stands in the bottom zone; on «medium» and «expanded» with the bar at the top it changes nothing. Rules — «x-style.layout.navFloat». No field — the bar as before 9.22.0. |
NavItem#
An item of the navigation bar: an icon, a label and the section it opens.
Since contract 9.12.0. Holds no children. Extra node fields: pin, showOn, styleOn, motion, pressFeedback.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
icon |
IconToken | yes | "house" |
|
label |
BindableString | yes | ||
action |
ButtonAction | yes | {"type":"none"} |
|
badgeWhen |
VisibilityCondition | no | Show a dot on the icon of the item while the condition holds (9.22.0): the same form, check and missing-data rule as «visibleIf». Only a dot, no number; its colour is the core token «accent». The accessible name stays the label. Rules — «x-style.layout.navBadge». No field or a condition the renderer does not understand — no dot. |
TextField#
A field the person types into: a label above, the field, a hint or an error below. What is typed is written to a data path.
Since contract 9.13.0. Holds no children. Extra node fields: pin, showOn, styleOn, motion, pressFeedback.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
label |
BindableString | yes | ||
value |
InputValue | no | ||
valueType |
TextFieldValueType | no | ||
required |
true |
no | Must be filled before a «requiresFilled» control of the screen is enabled («x-style.layout.form.required»). No field — not required. | |
placeholder |
BindableString | no | ||
helper |
BindableString | no | ||
error |
BindableString | no | ||
keyboard |
InputKeyboard | no | ||
maxLength |
integer 1–10000 | no | Limit of the entered text in Unicode code points; the renderer cuts the input to it. A counter is drawn only with «counter». | |
lines |
integer 1–8 | no | Visible lines of the field. More than one — a multiline field: Enter is a new line. No field — one line. | |
disabledIf |
VisibilityCondition | no | ||
fieldRadius |
RadiusRef | no | Radius of the box of the field itself (9.19.0): a token or a number. No field — «sm». Rules — «x-style.layout.inputParts.field». | |
fieldBackground |
ColorRef | no | Background of the box of the field (9.19.0). No field — «surface». Rules — «x-style.layout.inputParts.field». | |
fieldBorderColor |
ColorRef | no | Colour of the border of the field at rest (9.19.0); the colours of focus and error replace it as before. No field — «border». Rules — «x-style.layout.inputParts.field». | |
fieldBorderWidth |
integer 1–4 | no | Width of the border of the field in logical pixels (9.19.0), the same in every state. No field — 1. Rules — «x-style.layout.inputParts.field». | |
fieldHeight |
integer 32–120 | no | Exact height of the box of a ONE-LINE field in logical pixels (9.19.0); the text is centred. Not read by a multiline field. No field — border, padding and the line. Rules — «x-style.layout.inputParts.field». | |
prefix |
FieldAffix | no | ||
suffix |
FieldAffix | no | ||
counter |
true |
no | Draws «count / maxLength» under the field, at the end of the row of the helper (9.19.0); the count is in Unicode code points. Read only together with «maxLength». No field — no counter. Rules — «x-style.layout.inputParts.counter». |
Switch#
A row with a label and a switch at the end — a setting that applies at once. Writes yes or no to a data path.
Since contract 9.13.0. Holds no children. Extra node fields: pin, showOn, styleOn, motion, pressFeedback.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
label |
BindableString | yes | ||
value |
InputValue | no | ||
disabledIf |
VisibilityCondition | no |
Checkbox#
A row with a box and a label — a consent or a choice the person confirms. Writes yes or no to a data path.
Since contract 9.13.0. Holds no children. Extra node fields: pin, showOn, styleOn, motion, pressFeedback.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
label |
BindableString | yes | ||
value |
InputValue | no | ||
required |
true |
no | Must be filled before a «requiresFilled» control of the screen is enabled («x-style.layout.form.required»). No field — not required. | |
disabledIf |
VisibilityCondition | no |
ListTile#
One widget with slots, not an assembly: photo or icon, title with description, value or choice.
Since contract 1.0.0. Holds no children. Extra node fields: pin, showOn, styleOn, motion, pressFeedback.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
leading |
ListTileLeading | yes | {"kind":"icon","icon":"chevron"} |
|
title |
BindableString | yes | ||
subtitle |
BindableString | no | ||
titleMaxLines |
integer 1–5 | no | The largest number of lines of the title of the row (9.19.0); the rest is cut with an ellipsis at the end of the last line. No field — the text wraps without a limit, as before 9.19.0. Rules — «x-style.layout.listTileParts.maxLines». | |
subtitleMaxLines |
integer 1–5 | no | The largest number of lines of the subtitle of the row (9.19.0); the rest is cut with an ellipsis at the end of the last line. No field — the text wraps without a limit, as before 9.19.0. Rules — «x-style.layout.listTileParts.maxLines». | |
trailing |
ListTileTrailing | yes | {"kind":"chevron"} |
|
action |
ButtonAction | no | ||
longPress |
LongPressAction | no | ||
longPressLabel |
LongPressLabel | no |
Progress and status#
ProgressBar#
Progress bar: current value and limit, both can come from data.
Since contract 2.0.0. Holds no children. Extra node fields: pin, showOn, styleOn, motion, pressFeedback.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
value |
BindableNumber | yes | ||
max |
BindableNumber | yes | {"kind":"literal","value":100} |
|
color |
ColorRef | yes | "primary" |
|
labelFormat |
"valueOfMax" | "percent" | "none" |
yes | "valueOfMax" |
|
thickness |
SpacingRef | no | Thickness of the track and of the fill: the height of the bar track, the stroke of the ring arc. A spacing token or a whole number of dp. No field (or a token the theme does not declare) — «x-style.layout.progress.defaultThickness». A ring never draws thicker than half of its diameter; zero draws neither the track nor the fill. | |
trackColor |
ColorRef | no | Color of the track — the whole scale under the fill. No field (or a token the theme does not declare) — «x-style.layout.progress.defaultTrackColor». | |
gradient |
GradientRef | no | Gradient of the fill, stronger than «color» while it resolves. It runs along the FILLED part: position 0 — the start of the scale, position 1 — the end of the fill («x-style.layout.progress.gradient»); the angle is not read. No field, an unknown token or unordered stops — the fill is the solid «color». | |
cap |
"round" |
no | Ends of the scale (9.21.0). «round» — the ends of the ring arc and of the bar track and fill are half-circles of the thickness, kept INSIDE the filled part: geometry — «x-style.layout.progressCap». No field or an unknown word — square ends of the ring arc and the theme «pill» radius of the bar, exactly as before 9.21.0. | |
animateChanges |
true |
no | When the DATA change the value of this node while it is shown, the renderer leads from the old value to the new one (9.21.0): a number of a text with a numeric format counts through the values between, a scale grows. Duration, curve, steps and when there is no transition — «x-valueTransition». No field — the value changes at once, exactly as before 9.21.0. | |
animateIn |
true |
no | When the node is SHOWN, its value grows from zero to its own (9.24.0): a number of a text with a numeric format counts up from 0 with the same curve, duration and steps as «animateChanges»; a ProgressBar or CircularProgress fills from empty. Shown — the first show of the screen, a screen shown again («back»), a node that appears (condition, width class, a new record). Rules — «x-valueAppear». No field — the value is there at once, exactly as before 9.24.0. | |
glow |
ProgressGlow | no | ||
segments |
integer 2–12 | no | Cuts the scale into this many equal steps with a gap between them. A step is filled WHOLE or not at all: filled = floor(ratio × segments). Geometry, gap, rounding and the gradient — «x-style.layout.progressSegments». No field — the continuous bar. | |
currentColor |
ColorRef | no | Color of the CURRENT step — the first one that is not filled yet. Read only with «segments». No field (or a token the theme does not declare) — the current step looks like every other unfilled one. |
CircularProgress#
An arc around an empty center: how much of the scale is done. What goes in the center is decided by Stack.
Since contract 8.7.0. Holds no children. Extra node fields: pin, showOn, styleOn, motion, pressFeedback.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
value |
BindableNumber | yes | ||
max |
BindableNumber | yes | {"kind":"literal","value":100} |
|
color |
ColorRef | yes | "primary" |
|
size |
"sm" | "md" | "lg" |
yes | "md" |
Diameter of the ring when the node names no size of its own: «sm» — around a badge, «md» — a rank in a ring, «lg» — the main ring of the screen («x-style.layout.progress.ring.sizes»). A node with «style.width» or «style.height» takes its diameter from them instead (9.7.0). |
labelFormat |
"valueOfMax" | "percent" | "none" |
no | "none" |
Label in the CENTER of the ring: «percent» — «75%», «valueOfMax» — «3/4», «none» — nothing, and the center stays free for a Stack layer. Unlike the progress bar, the default here is «none»: the center is space the contract already promised to the document. |
thickness |
SpacingRef | no | Thickness of the track and of the fill: the height of the bar track, the stroke of the ring arc. A spacing token or a whole number of dp. No field (or a token the theme does not declare) — «x-style.layout.progress.defaultThickness». A ring never draws thicker than half of its diameter; zero draws neither the track nor the fill. | |
trackColor |
ColorRef | no | Color of the track — the whole scale under the fill. No field (or a token the theme does not declare) — «x-style.layout.progress.defaultTrackColor». | |
gradient |
GradientRef | no | Gradient of the fill, stronger than «color» while it resolves. It runs along the FILLED part: position 0 — the start of the scale, position 1 — the end of the fill («x-style.layout.progress.gradient»); the angle is not read. No field, an unknown token or unordered stops — the fill is the solid «color». | |
cap |
"round" |
no | Ends of the scale (9.21.0). «round» — the ends of the ring arc and of the bar track and fill are half-circles of the thickness, kept INSIDE the filled part: geometry — «x-style.layout.progressCap». No field or an unknown word — square ends of the ring arc and the theme «pill» radius of the bar, exactly as before 9.21.0. | |
animateChanges |
true |
no | When the DATA change the value of this node while it is shown, the renderer leads from the old value to the new one (9.21.0): a number of a text with a numeric format counts through the values between, a scale grows. Duration, curve, steps and when there is no transition — «x-valueTransition». No field — the value changes at once, exactly as before 9.21.0. | |
animateIn |
true |
no | When the node is SHOWN, its value grows from zero to its own (9.24.0): a number of a text with a numeric format counts up from 0 with the same curve, duration and steps as «animateChanges»; a ProgressBar or CircularProgress fills from empty. Shown — the first show of the screen, a screen shown again («back»), a node that appears (condition, width class, a new record). Rules — «x-valueAppear». No field — the value is there at once, exactly as before 9.24.0. | |
glow |
ProgressGlow | no | ||
labelTypography |
TypographyRef | no | Font style of the label in the center of the ring (9.17.0): a theme token or a token with overrides. No field — «x-style.layout.progress.ring.labelTypography». The label does not scale with the diameter. | |
labelColor |
ColorRef | no | Colour of the label in the center of the ring (9.17.0). No field — «x-style.layout.progress.ring.labelColor». |
Badge#
A short label in color that means a state: success, warning, accent. With an icon and its own colors it is the chip of a design: «4 days left», «LIMITED».
Since contract 2.0.0. Holds no children. Extra node fields: pin, showOn, styleOn, motion, pressFeedback.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
label |
BindableString | yes | ||
tone |
"neutral" | "success" | "warning" | "danger" | "accent" |
yes | "neutral" |
|
icon |
IconToken | no | Icon beside the label, by the same rule as in a button («x-style.layout.iconBesideText»). No field — no icon. | |
iconPath |
IconPath | no | ||
iconPosition |
IconPosition | no |
How a style is read#
The rules below are the x-style and x-tokens blocks of the schema artifact, in words. They are part of the contract: two renderers that read them differently draw the same document differently.
Box model. Outside is margin; then the box — size, background, border, radius, shadow, opacity; inside it padding; inside that, what the widget draws. A size (width, height) is the size of the box including its border and padding.
- A node without
stylehas no background, no padding and no radius (hiddenDefaults:"none"). The builder writes the usual look of a card into the document; a renderer adds nothing of its own. - Sides and corners are logical —
startandend, not left and right (sides:"logical"). A side or corner that is not named is zero (unnamedSide:"zero"). - A node
weightoverridesstyle.width(weightOverridesWidth:true), and afilllayer overrides bothstyle.widthandstyle.height(fillOverridesSize:true). Each size goes together with itsmin…andmax…. - The share of a row that a
weightgives is the whole place of the node, its ownmarginincluded (weightShareIncludes): the margin lies inside the share and the box inside the margin. In CSS the element that carriesflex: N 1 0must not be the one that carries the margin. - The corner radius clips the background and the content, children included (
background,content); the shadow lies outside and is not clipped.opacityapplies tobackground,border,shadow,contenttogether, as one box. - The root of a screen has no
margin,width,height,minWidth,maxWidth,minHeight,maxHeight(a separateScreenStylein the schema). A renderer that receives them ignores them and applies the rest of the style.
States. The first case of styleWhen whose condition holds applies (caseSelection: "first-match"). It is laid over the base style by top-level fields (caseMerge: "top-level-fields"): a case with padding replaces padding as a whole, not side by side. With no matching case the base style applies.
Inheritance. color, typography pass down the tree, after the state is applied (inheritance: "after-case-merge"). At the root of a screen they are color: onSurface and typography: bodyM. A text style is inherited as a whole, not edit by edit.
| Inherited field | Widgets that read it |
|---|---|
color |
Text, Icon, ListTile, AppBar, Tab, NavItem, Accordion |
typography |
Text |
Only Text reads the text style. Button, IconButton and Badge read neither: their look comes from the theme role (below). The composite widgets read the color part by part, from the table below.
Which part reads a named color (colorParts). A primary part takes the color as it is. A secondary part takes the same color with opacity 0.6 (secondaryOpacity): a token becomes a tint of that token, not a value of its own. whenUnnamed says what to draw until nobody has named a color: root — the root onSurface; built-in — the widget's own built-in colors, as before 9.0.0.
| Widget | Part | Emphasis | Until a color is named |
|---|---|---|---|
Text |
content |
primary |
root |
Icon |
glyph |
primary |
root |
ListTile |
title |
primary |
built-in |
ListTile |
subtitle |
secondary |
built-in |
ListTile |
leadingIcon |
primary |
built-in |
ListTile |
trailingText |
primary |
built-in |
ListTile |
trailingIcon |
primary |
built-in |
ListTile |
chevron |
secondary |
built-in |
AppBar |
title |
primary |
built-in |
AppBar |
subtitle |
secondary |
built-in |
AppBar |
backIcon |
primary |
built-in |
Tab |
activeTitle |
primary |
built-in |
Tab |
inactiveTitle |
secondary |
built-in |
NavItem |
activeItem |
primary |
built-in |
NavItem |
inactiveItem |
secondary |
built-in |
Accordion |
title |
primary |
built-in |
Accordion |
chevron |
secondary |
built-in |
A color counts as named when the node itself or an ancestor sets style.color — even to onSurface. Keep that as a flag in the inheritance context; comparing the color with the root color misses a card that names the root color on purpose. A color the theme does not declare is not named and not inherited: the parent value stays (unknownInheritedToken: keep-parent).
The leading icon of a ListTile is a plain glyph with no disc under it, and it reads the named color (leadingIcon). The photo, the radio circle, the active tab bar and the dividers do not read a named color.
Widgets with a role. The look of these widgets comes from a role of the theme by default (default: "theme-role"):
| Widget | Property that names the role | Group in theme.roles |
|---|---|---|
Button |
variant |
buttonVariant |
IconButton |
variant |
buttonVariant |
Badge |
tone |
badgeTone |
- The role gives the background, the label color and the border; a role border is 1 logical pixel wide.
- These fields of the node's own
style— base style with the active state — override the role, each one separately (override:"own-style-per-slot"):background,color,border,radius,shadow,padding,typography. - They apply to the surface of the widget itself — the button, the pill — and are not applied a second time to the box around it (
appliesTo:"widget-surface").margin, sizes andopacitydescribe the box, as on every node. - A color inherited from an ancestor does not override the role (
inheritedColor:"does-not-override-role").
Token names. The theme declares them; the schema checks only the shape of a name: ^[a-z][a-zA-Z0-9]{0,39}$. Every theme has the core names below, and may add up to 64 of its own per dictionary.
| Dictionary | Core names |
|---|---|
color |
primary, onPrimary, secondary, accent, surface, onSurface, muted, border, success, warning, danger, locked, inProgress, completed |
gradient |
brandBackdrop |
spacing |
none, xs, sm, md, lg, xl |
radius |
none, sm, md, lg, pill |
elevation |
none, low, medium |
typography |
displayL, titleM, titleS, bodyM, bodyS, caption, numericL |
The three state colors — locked, inProgress, completed — are listed with the core because a document may always name them, but a theme may leave them out: they have documented fallbacks. See theme.
Gradient geometry (x-gradientGeometry). A custom gradient and a gradient of the theme are drawn in the same way.
coordinates: normalized box: (0,0) top-left, (1,1) bottom-right, y grows downwardsaxis: as CSS: 0 — to top, 90 — to right, 180 — to bottom, 270 — to left; from the middle of one edge to the middle of the opposite edgediagonal: exactly CSS «to <corner>»: 45 — to top right, 135 — to bottom right, 225 — to bottom left, 315 — to top left. The gradient line passes through the center perpendicular to the diagonal joining the two OTHER corners, so the 50% isoline passes through those two corners and the target corner gets position 1formula: for a box w×h and direction signs (sx, sy): end = (0.5 + sx·h²/(w²+h²), 0.5 + sy·w²/(w²+h²)), start is symmetric about the center; in Flutter: Alignment(2x−1, 2y−1)direction: physical: not mirrored in right-to-left scriptsequalStops: ordered
What a renderer does with a token the theme does not declare, with a style field it does not know, with gradient stops that go backwards and with a minimum size above the maximum is on the compatibility page.
Shared types#
Types the tables above link to. A token type names a value the project theme declares. A …Ref type accepts a token or a value of the document's own within the limits shown; the token is the shorter form and the one a rebrand moves.
SpacingRef#
One of:
- SpacingToken
- integer 0–128
SpacingToken#
Name of a «spacing» token of the project theme. The schema checks only the shape of the name; whether the theme declares it is a semantic rule checked against the active theme.
string matching ^[a-z][a-zA-Z0-9]{0,39}$.
AlignToken#
One of: "start", "center", "end".
ColorRef#
One of:
- ColorToken
- {
token: ColorToken,opacity: number 0–1 } - {
value: string matching^#[0-9a-f]{6}$,opacity?: number 0–1 }
ColorToken#
Name of a «color» token of the project theme. The schema checks only the shape of the name; whether the theme declares it is a semantic rule checked against the active theme.
string matching ^[a-z][a-zA-Z0-9]{0,39}$.
TypographyRef#
One of:
TypographyToken#
Name of a «typography» token of the project theme. The schema checks only the shape of the name; whether the theme declares it is a semantic rule checked against the active theme.
string matching ^[a-z][a-zA-Z0-9]{0,39}$.
TypographyOverride#
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
token |
TypographyToken | yes | ||
fontSize |
number 8–96 | no | ||
fontWeight |
integer 100–900 | no | ||
lineHeight |
number 0.8–3 | no | ||
letterSpacing |
number -2–8 | no |
TextFontStyle#
One of: "normal", "italic".
TextDecoration#
One of: "none", "underline", "lineThrough".
GradientRef#
One of:
GradientToken#
Name of a «gradient» token of the project theme. The schema checks only the shape of the name; whether the theme declares it is a semantic rule checked against the active theme.
string matching ^[a-z][a-zA-Z0-9]{0,39}$.
CustomGradient#
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
angle |
0 | 90 | 180 | 270 | 45 | 135 | 225 | 315 |
yes | ||
stops |
array of object { color, position } (min 2, max 8) |
yes |
BoxSpacing#
One of:
SpacingSides#
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
top |
SpacingRef | no | ||
end |
SpacingRef | no | ||
bottom |
SpacingRef | no | ||
start |
SpacingRef | no |
BoxRadius#
One of:
RadiusRef#
One of:
- RadiusToken
- integer 0–256
RadiusToken#
Name of a «radius» token of the project theme. The schema checks only the shape of the name; whether the theme declares it is a semantic rule checked against the active theme.
string matching ^[a-z][a-zA-Z0-9]{0,39}$.
RadiusCorners#
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
topStart |
RadiusRef | no | ||
topEnd |
RadiusRef | no | ||
bottomEnd |
RadiusRef | no | ||
bottomStart |
RadiusRef | no |
NodeBorder#
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
width |
number 0.5–16 | yes | ||
color |
ColorRef | yes | ||
style |
"dashed" |
no | Line of the border (9.22.0). «dashed» — dashes of 3 and gaps of 2 border widths along the centre line of the border, following the corner arcs; the count closes the loop evenly. Rules — «x-style.layout.borderDash». No field or an unknown word — solid, exactly as before 9.22.0. |
NodeBackground#
One of:
- {
kind:"color",color: ColorRef } - {
kind:"gradient",gradient: GradientRef } - {
kind:"image",source: ImageSource,fit:"cover"|"contain"}
ImageSource#
One of:
- {
kind:"asset",asset: AssetToken } - {
kind:"url",url: string (length 0–2048) } - {
kind:"binding",path: non-empty string,fallback: AssetToken }
AssetToken#
One of: "logo", "banner", "placeholder".
ShadowRef#
One of:
- ElevationToken
- array of CustomShadowLayer (min 1, max 4)
ElevationToken#
Name of a «elevation» token of the project theme. The schema checks only the shape of the name; whether the theme declares it is a semantic rule checked against the active theme.
string matching ^[a-z][a-zA-Z0-9]{0,39}$.
CustomShadowLayer#
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
offsetX |
number -64–64 | yes | ||
offsetY |
number -64–64 | yes | ||
blur |
number 0–128 | yes | ||
spread |
number -64–64 | yes | ||
color |
ColorRef | yes |
ShadowColor#
Colour of the shadow (9.25.0): «background» — every layer of «shadow» (a token or own layers) takes the hue of the own background of this node, keeping the opacity of the layer: a solid background gives its colour, a gradient the stop nearest to its middle. No background, an image background or a colour that does not resolve — the shadow keeps its own colour. Rules — «x-shadowColor». No field — the shadow keeps its own colour, exactly as before 9.25.0.
One of: "background".
VisibilityCondition#
One of:
- UnaryVisibilityCondition
- EqualityVisibilityCondition
- OrderVisibilityCondition
- PathComparisonCondition
- FilteredEmptinessCondition
UnaryVisibilityCondition#
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
path |
non-empty string | yes | ||
op |
"isTrue" | "isFalse" | "isEmpty" | "isNotEmpty" |
yes |
EqualityVisibilityCondition#
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
path |
non-empty string | yes | ||
op |
"eq" | "neq" |
yes | ||
value |
string (length 0–128) | number | boolean | yes |
OrderVisibilityCondition#
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
path |
non-empty string | yes | ||
op |
"gt" | "gte" | "lt" | "lte" |
yes | ||
value |
number | yes |
PathComparisonCondition#
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
path |
non-empty string | yes | ||
op |
"eq" | "neq" | "gt" | "gte" | "lt" | "lte" |
yes | ||
valuePath |
non-empty string | yes | The operand is the value under this OTHER data path (9.23.0), read in the same scope as «path»: «reward.category eq ui.rewardsCategory». No value under it (or the empty string) — see «x-listFilter.operandMissing». |
FilteredEmptinessCondition#
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
path |
non-empty string | yes | ||
op |
"isEmpty" | "isNotEmpty" |
yes | ||
item |
non-empty string | yes | Prefix of a record of the collection, as «Repeater.item» (9.23.0). | |
where |
ListWhereCondition | yes | Count only the records for which this condition holds (9.23.0) — the same predicate as «Repeater.where». Rules — «x-listFilter.emptiness». |
ListWhereCondition#
One of:
- UnaryVisibilityCondition
- EqualityVisibilityCondition
- OrderVisibilityCondition
- PathComparisonCondition
BindableString#
One of:
- {
kind:"literal",value: string } - {
kind:"binding",path: non-empty string,fallback: string,format?: BindingFormat,currency?: CurrencyCode,currencyDisplay?: CurrencyDisplay,currencyPosition?: CurrencyPosition,sign?: NumberSign,dateParts?: DateParts,unit?: CountdownUnit,pad?:2,notation?: NumberNotation } - {
kind:"template",template: string,values: object }
BindingFormat#
One of: "date", "dateTime", "time", "number", "currency", "daysUntil", "countdownPart".
CurrencyCode#
An ISO 4217 currency code: three capital letters (USD, JOD). Required exactly when format is currency.
string matching ^[A-Z]{3}$.
CurrencyDisplay#
Money (9.19.0): symbol shows the currency by its sign from «x-money.symbols» instead of the code. A code the table does not have is shown as the code. Only with format: currency. No field — the code.
One of: "symbol".
CurrencyPosition#
Money (9.19.0): before puts the currency before the amount — a sign with no gap, a code with U+00A0. Only with format: currency. No field — after the amount, with U+00A0.
One of: "before".
NumberSign#
Sign of a number (9.19.0): always writes «+» before a positive number. Zero has no sign. With format: number or currency. No field — a negative number only, as the platform writes it.
One of: "always".
DateParts#
Which parts of a date to show, beside «format: date» (9.19.0): «dayMonth» — day and month in full, no year; «weekdayDayMonth» — the day of the week, day and month in full; «dayMonthYear» — day, month in full and year. Order and separators come from CLDR for the formatting locale. Rules — «x-dateParts». No field — year, short month and day, exactly as before 9.19.0. A word the renderer does not know — the field is absent.
One of: "dayMonth", "weekdayDayMonth", "dayMonthYear".
CountdownUnit#
Which part of the time left the «countdownPart» format shows (9.21.0): «days» — whole days; «hours» — 0–23; «minutes» — 0–59; «seconds» — 0–59. Required exactly when «format» is «countdownPart». Arithmetic, ticking and the clock — «x-countdown».
One of: "days", "hours", "minutes", "seconds".
NumberNotation#
Compact number (9.23.0): «compact» writes 48 200 as «48.2K» (en) or «48,2 тис.» (uk) — one fraction digit, half up, suffixes from a closed table by language. Only with «format: number». Rules — «x-compactNumber». No field — every digit.
One of: "compact".
NodeStyle#
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
color |
ColorRef | no | ||
typography |
TypographyRef | no | ||
fontStyle |
TextFontStyle | no | Slant of the text (9.17.0). Inherited down the tree like «typography»; read by Text only. «normal» cancels an inherited italic. | |
textDecoration |
TextDecoration | no | Line under or through the text (9.17.0), in the colour of the text. Inherited down the tree; read by Text only. «none» cancels an inherited line. | |
textGradient |
GradientRef | no | Gradient painted on the GLYPHS of the text (9.23.0): a gradient token of the theme or an own gradient of the same form as a gradient «background». It lies over the whole content box of the text, not line by line; a part of the text that names its own colour keeps it. «color» stays the fallback: an older renderer and a gradient that does not resolve paint the text with it. Not inherited; read by Text only. Rules — «x-textGradient». | |
padding |
BoxSpacing | no | ||
margin |
BoxSpacing | no | ||
width |
Dimension | no | ||
height |
Dimension | no | ||
minWidth |
Dimension | no | ||
maxWidth |
Dimension | no | ||
minHeight |
Dimension | no | ||
maxHeight |
Dimension | no | ||
radius |
BoxRadius | no | ||
border |
NodeBorder | no | ||
background |
NodeBackground | no | ||
shadow |
ShadowRef | no | ||
shadowColor |
ShadowColor | no | ||
opacity |
number 0–1 | no | ||
backdropBlur |
integer 1–40 | no | Blur of whatever is painted UNDER the box of this node, clipped by its «radius» (9.20.0) — frosted glass on a card, a navigation bar or a button. Logical pixels, the standard deviation of a Gaussian blur; the node own background lies over the blur, the node and its children are never blurred. Not inherited. No field — no blur. Rules — «x-backdropBlur.style». |
Dimension#
One of:
- number 1–1200
- {
kind:"binding",path: non-empty string,fallback: number 1–1200 }
StyleCase#
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
when |
VisibilityCondition | yes | ||
style |
NodeStyle | yes |
NodeWeight#
Share of the row width this child takes. Children with a weight split the row in proportion to their weights; children without one keep their natural width. A weight overrides the widget own width. Legal only inside a row of finite width: the «Row» widget without «wrap» and without «scrollable», or a «Container» with direction «row». No field — the child keeps its natural width, exactly as before 8.17.0.
integer 1–4.
NodeLayer#
Placement of this layer inside a «Stack» (9.10.0). A layer with this field is an OVERLAY: it is positioned against the box of the stack and never changes the size of the stack. «alignHorizontal» / «alignVertical» — its own alignment (no key — the alignment of the stack); «offset» — a shift from that place along the axes of the stack («x.toward»: start | end, logical; «y.toward»: top | bottom; «by» — a spacing token or logical pixels); «rotate» — whole degrees clockwise about the centre of the layer, mirrored in RTL. The layer may stick out of the stack; who clips it and where it catches a tap — «x-style.layout.layer». Legal only on a direct child of «Stack» and not together with «fill». No field — an ordinary layer, exactly as before 9.10.0.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
alignHorizontal |
AlignToken | no | ||
alignVertical |
AlignToken | no | ||
offset |
LayerOffset | no | ||
rotate |
integer -180–180 | no |
LayerOffset#
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
x |
object { toward, by } |
no | ||
y |
object { toward, by } |
no |
NodePull#
Pulls this child towards the START of the main axis of its parent by this much (9.10.0): the child and everything after it move, so the child lies OVER what precedes it and the parent gets shorter by the same amount. The gap of the parent stays: the overlap is «pull» minus the gap. A spacing token or logical pixels. Legal only where children follow one another: «Screen», «Column», «Container», and a «Row» without «wrap» and without «scrollable»; not together with «weight». Rules — «x-style.layout.pull». No field — the child stands where the flow puts it, exactly as before 9.10.0.
PressAction#
Makes the whole container pressable (9.19.0): the same action form and the same execution path as a button. The container is a control when the action type is not «none» or the action carries «track». A control inside it (a button, an input, a choice option, a list row with an action) takes its own press — the container gets the rest of its box. No field — a plain container, exactly as before 9.19.0.
ButtonAction#
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
type |
string (length 1–64) | yes | ||
params |
object | no | ||
paramBindings |
object | no | Parameter name → data-contract path. At press time the renderer reads the path with the data scope of the node; a non-empty string replaces the literal in «params», anything else leaves the literal (the fallback). | |
carryRecord |
true |
no | Only on «navigate»: the opened screen gets the record scope of this node even when it is a page opened from outside a list row. Absent — the rule of 9.2.0. | |
track |
ActionTrack | no | ||
haptic |
"light" | "medium" | "heavy" | "selection" | "success" | "warning" |
no | Haptic feedback of the press (9.25.0) — a REQUEST to the host, like «track»: the renderer never vibrates by itself, it hands the word to the host once per press, before the action and next to the analytics event. «light», «medium», «heavy» — an impact; «selection» — a change of choice; «success», «warning» — an outcome. Rules — «x-haptic». No field — no request. |
ActionTrack#
Analytics event of the press. Handed to the host once per press, before the action is performed, with the same source as the action. Not an action: any action may carry it.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
event |
string matching `^(?!(?:constructor | prototype)$)[A-Za-z][A-Za-z0-9_]*$` | yes | |
params |
object | no |
PressLabel#
Hidden accessible name of a pressable container (9.19.0): read first, before the text of its content. Required when nothing inside the container says anything without data.
LongPressAction#
Long press of the node (9.26.0): the same action form and execution path as «action». It fires while the finger is still down, once it has stayed within the touch slop for the threshold of «x-longPress»; the press of «action» then does not happen. Only on a pressable container and on ListTile — never on a button. Requires «longPressLabel». No field — no long press.
LongPressLabel#
Name of the long press action for assistive technologies (9.26.0): a named custom action of the node, the context menu key and Shift+F10. Required when «longPress» does something. Translatable.
Carousel#
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
perView |
integer 1–6 | no | How many WHOLE cards the viewport shows; every card then has the same width — (viewport − inline-start padding − perView × gap − peek) ÷ perView — and its own «style.width» is not read. No field — cards keep the width a scrolling row gives them («x-style.layout.scrollableRow»). | |
peek |
SpacingRef | no | How much of the NEXT card shows at the inline end of the viewport. Read only with «perView». No field (or a token the theme does not declare) — «x-style.layout.carousel.card.defaultPeek». | |
indicator |
"dots" | "none" |
no | The dots under the carousel: one per snap stop, the active one follows the scroll. No field or an unknown word — «x-style.layout.carousel.indicator.default». |
ContainerDirection#
One of: "column", "row".
BindableString64#
One of:
- {
kind:"literal",value: string (length 0–64) } - {
kind:"binding",path: non-empty string,fallback: string (length 0–64),format?: BindingFormat,currency?: CurrencyCode,currencyDisplay?: CurrencyDisplay,currencyPosition?: CurrencyPosition,sign?: NumberSign,dateParts?: DateParts,unit?: CountdownUnit,pad?:2,notation?: NumberNotation }
Orientation#
The axis of a «Spacer» or a «Divider», named after the SHAPE of the widget, not after the layout around it. «horizontal»: the divider is a horizontal line and the spacer adds HEIGHT — the form used inside a column. «vertical»: the divider is a vertical line and the spacer adds WIDTH — the form used inside a row. The container dictates the axis: a column needs «horizontal», a row needs «vertical».
One of: "horizontal", "vertical".
TextMarker#
One of: "none", "bullet", "number".
ImageRatio#
Proportion of the image frame: a word of the list or an own «width : height» pair (9.9.0). It gives the HEIGHT of the box from its width, and only when «style.height» does not name it: a named size of the node box is stronger («x-style.layout.image»). A renderer that does not know the value uses «16:9».
One of:
"1:1"|"16:9"|"4:3"- CustomImageRatio
CustomImageRatio#
Own proportion of the image frame: «width» to «height», two integers. Only their RATIO matters — «343 × 120» and «686 × 240» are the same frame. The ratio must stay within «x-style.layout.image.ratioRange»; a renderer clamps what is outside it.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
width |
integer 1–1200 | yes | ||
height |
integer 1–1200 | yes |
AltText#
Description for a screen reader. A plain string — the text in the default language of the document, translated under the key of the field itself (<screenId>/<nodeId>/alt); or, from 9.19.0, a string of the document — a binding to data or a template, read and translated as any other. A wrapped literal equals the plain string. A renderer older than 9.19 hears the plain string and reads an object as «no description».
One of:
- string
- BindableString
IconToken#
One of: "star", "trophy", "gift", "target", "clock", "check", "chevron", "user", "info", "lock", "accessibility", "activity", "alarm-clock", "anchor", "apple", "archive", "arrow-down", "arrow-down-left", "arrow-down-right", "arrow-left", "arrow-right", "arrow-up", "arrow-up-left", "arrow-up-right", "award", "baby", "backpack", "badge-check", "badge-dollar-sign", "badge-percent", "ban", "bandage", "banknote", "battery", "battery-charging", "battery-full", "bed", "beer", "bell", "bell-off", "bell-ring", "biceps-flexed", "bike", "bird", "book", "book-open", "bookmark", "bookmark-check", "bot", "box", "briefcase", "building", "bus", "cake", "calculator", "calendar", "calendar-check", "calendar-clock", "calendar-days", "calendar-plus", "camera", "car", "cat", "chart-bar", "chart-column", "chart-line", "chart-pie", "check-check", "cherry", "chevron-down", "chevron-left", "chevron-right", "chevron-up", "chevrons-down", "chevrons-left", "chevrons-right", "chevrons-up", "circle", "circle-alert", "circle-arrow-down", "circle-arrow-left", "circle-arrow-right", "circle-arrow-up", "circle-check", "circle-chevron-left", "circle-chevron-right", "circle-dollar-sign", "circle-help", "circle-minus", "circle-percent", "circle-play", "circle-plus", "circle-star", "circle-user", "circle-x", "clipboard", "clipboard-list", "clock-alert", "cloud", "cloud-download", "cloud-lightning", "cloud-rain", "cloud-snow", "cloud-sun", "cloud-upload", "code", "coffee", "coins", "compass", "contact", "cookie", "copy", "credit-card", "crown", "database", "diamond", "dice-5", "dices", "dog", "dollar-sign", "door-open", "download", "droplet", "dumbbell", "ellipsis", "ellipsis-vertical", "euro", "external-link", "eye", "eye-off", "file", "file-plus", "file-text", "fingerprint-pattern", "fish", "flag", "flame", "flower", "folder", "folder-open", "folder-plus", "footprints", "forward", "frown", "fuel", "funnel", "gamepad-2", "gauge", "gem", "glasses", "globe", "goal", "graduation-cap", "hamburger", "hand", "hand-coins", "hand-heart", "handshake", "headphones", "headset", "heart", "heart-handshake", "heart-pulse", "history", "hospital", "hotel", "hourglass", "house", "ice-cream-cone", "id-card", "image", "images", "inbox", "infinity", "key", "lamp", "landmark", "languages", "laugh", "layout-grid", "layout-list", "leaf", "lightbulb", "link", "list", "list-checks", "list-ordered", "loader-circle", "lock-open", "log-in", "log-out", "luggage", "mail", "mail-open", "map", "map-pin", "medal", "megaphone", "menu", "message-circle", "message-square", "mic", "minus", "monitor", "moon", "mountain", "music", "navigation", "newspaper", "package", "package-check", "package-open", "paintbrush", "palette", "paperclip", "party-popper", "pause", "paw-print", "pencil", "percent", "phone", "phone-call", "piggy-bank", "pill", "pin", "pizza", "plane", "plane-landing", "plane-takeoff", "play", "plus", "podium", "popcorn", "pound-sterling", "printer", "puzzle", "qr-code", "rainbow", "receipt", "recycle", "redo", "redo-2", "refresh-ccw", "refresh-cw", "repeat", "reply", "ribbon", "rocket", "rotate-ccw", "rotate-cw", "route", "save", "scale", "scan", "scan-face", "school", "scissors", "search", "send", "settings", "share", "share-2", "shield", "shield-check", "ship", "shirt", "shopping-bag", "shopping-basket", "shopping-cart", "shuffle", "signpost", "skip-back", "skip-forward", "sliders-horizontal", "smartphone", "smile", "snowflake", "sofa", "sparkles", "sprout", "square-check", "square-pen", "star-half", "stethoscope", "store", "sun", "tag", "tags", "tent", "thermometer", "thumbs-down", "thumbs-up", "ticket", "ticket-check", "ticket-percent", "tickets", "timer", "timer-reset", "toggle-left", "toggle-right", "train-front", "trash-2", "tree-pine", "trending-down", "trending-up", "triangle-alert", "truck", "tv", "umbrella", "undo", "undo-2", "upload", "user-check", "user-plus", "user-round", "user-x", "users", "utensils", "video", "volume-2", "volume-x", "wallet", "wand-sparkles", "watch", "waves", "wifi", "wifi-off", "wind", "wine", "wrench", "x", "zap".
IconPath#
Path in the data dictionary that holds the NAME of an icon of the contract icon set (9.19.0). The name of the document stays beside it: it is drawn when the data has no value (absent, null, an empty string) and by a renderer older than 9.19. A name that is not in the set, or a value that is not a string, is an empty box of the same size. Never an address or a drawing. Rules — «x-iconFromData». No field — the icon of the document, exactly as before 9.19.0.
string (length 1–128).
IconPosition#
Where the icon stands relative to the text beside it, in READING order: «start» — before the text (on the left in LTR, on the right in RTL), «end» — after it. The renderer never swaps the two by itself; the direction of the script does. No field — «start» («x-style.layout.iconBesideText.defaultPosition»). Without an icon the field means nothing.
One of: "start", "end".
ButtonSize#
Size of a button. The padding and the text style of each size are data of the contract («x-style.layout.buttonSizes»), expressed in theme tokens. No field — «md» («x-style.layout.defaultButtonSize»), the button as it was before 9.5.0.
One of: "sm", "md", "lg".
ListTileLeading#
One of:
- {
kind:"none"} - {
kind:"icon",icon: IconToken,color?: ColorRef,tile?: ListTileLeadingTile } - {
kind:"image",source: ImageSource }
ListTileLeadingTile#
A tinted square (or circle — radius «pill») under the leading icon of a list row (9.19.0). The tile takes the place of the icon in the row; the gap to the texts is unchanged. Rules — «x-style.layout.listTileParts.leading.tile».
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
color |
ColorRef | yes | Background of the tile: a token, a token with opacity («10 % of the brand colour») or an own colour. | |
radius |
RadiusRef | no | Radius of the tile: a token or a number. No field — «sm», the radius of the leading image. | |
size |
integer 24–96 | no | Side of the square tile in logical pixels. No field — 40. The glyph keeps its size and stands in the centre. |
ListTileTrailing#
One of:
- {
kind:"none"} - {
kind:"text",text: BindableString,icon?: IconToken,style?: PartStyle,styleWhen?: array of PartStyleCase (min 1, max 4),caption?: BindableString,captionStyle?: PartStyle,captionStyleWhen?: array of PartStyleCase (min 1, max 4) } - {
kind:"chevron"} - {
kind:"radio",optionValue: string (length 1–64) }
PartStyle#
Colour and typography of ONE part of a composite widget (9.19.0), named apart from the node: token or own value, like a field of «style». A field that is not named is not applied: the part keeps what it had (the named colour of the node or the built-in one). A token the theme does not know — the field is skipped. Rules — «x-style.layout.partStyle».
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
color |
ColorRef | no | ||
typography |
TypographyRef | no |
PartStyleCase#
One state of a part: the condition of the same form as «visibleIf» and the style laid over the base style of the part while it holds.
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
when |
VisibilityCondition | yes | ||
style |
PartStyle | yes |
BindableNumber#
One of:
- {
kind:"literal",value: number } - {
kind:"binding",path: non-empty string,fallback: number }
ProgressGlow#
Glow of the FILLED part of the scale (9.25.0): a blurred copy of the fill under it, in its own colour or gradient — «soft» or «strong», numbers in «x-progressGlow». A bar with steps lights one step: the current one when «currentColor» paints it, otherwise the last step with any fill. It changes no layout and is not clipped by the own box of the node. No field or an unknown word — no glow, exactly as before 9.25.0.
One of: "soft", "strong".
InputValue#
Where an input reads its value and writes the change: a path of the data contract. Read through the data layers («x-dataScope.layers»); written to the session of the renderer and handed to the host. No literal and no fallback: an input without data is empty (a toggle is off).
| Property | Type | Required | Default | Notes |
|---|---|---|---|---|
kind |
"binding" |
yes | ||
path |
non-empty string | yes |
TextFieldValueType#
What a text field holds and writes. «number» — a path of type number, the numeric keyboard, a JSON number is written («x-style.layout.form.number»). No field or an unknown word — «string».
One of: "string", "number".
InputKeyboard#
Intent of the screen keyboard of a text field, not a platform attribute: what each word becomes on the web and in Flutter is data («x-style.layout.inputs.textField.keyboards»). No field or an unknown word — «text». Not read by a multiline field.
One of: "text", "email", "number", "phone", "url".
FieldAffix#
A mark inside the box of a text field (9.19.0): a short text («₴», «kg») or an icon, at the logical start («prefix») or end («suffix») of the box by the direction of the SCREEN. It is not part of the value and is never written. Rules — «x-style.layout.inputParts.affix».
One of:
- {
kind:"text",text: BindableString } - {
kind:"icon",icon: IconToken }