Widget reference

← State · Documentation · Next: Actions →

This page is the complete reference for built-in widgets: envelope clicks and modifiers, params, defaults, children, events, write-back, and examples.

Common rules

Envelope fields (id, state, modifier, onClick, params, children, observers, theme, minSpec) are documented in architecture. modifier and onClick are not params.

EnvelopeTypeDefaultMeaning
modifiermodifier[][]Applied left-to-right; see themes
onClickactionabsentMakes any widget clickable. Absent means not clickable
ParamTypeDefaultMeaning
visibleboolean/pathtruefalse removes the widget from composition and layout
enabledboolean/pathtrueDisables interaction, including envelope onClick

Any widget type may set envelope onClick. BDUI applies clickable; it is not a Card/Button-only param. params.enabled: false suppresses it. A child's onClick consumes the click so ancestors do not also fire. Widget-specific flags such as Button loading also suppress it.

  • Params may be compatible literals or explicit paths.
  • Unknown params are ignored and logged in debug builds.
  • Invalid/missing values use the stated safe default.
  • Only containers render children; leaves ignore accidental children.
  • Unknown/too-new widget types skip their complete subtree.
  • Dimensions use dp (including width / height modifiers), not device pixels; text sizes use sp.
  • User font scale, contrast, and platform accessibility settings win.

Index

LayoutContentInput
[Column](#column)[Text](#text)[Checkbox](#checkbox)
[Row](#row)[Image](#image)[Switch](#switch)
[Box](#box)[Button](#button)[Chip](#chip)
[Card](#card)[CircularProgress](#circularprogress)[TextField](#textfield)
[Scaffold](#scaffold)[LinearProgress](#linearprogress)[Slider](#slider)
[TopAppBar](#topappbar)[FloatingActionButton](#floatingactionbutton)[RadioGroup](#radiogroup)
[LazyColumn](#lazycolumn)[Chart](#chart)[Radio](#radio)
[Calendar](#calendar)[Review](#review)[Select](#select)
[Spacer](#spacer)
[Divider](#divider)
[Stepper](#stepper)

Layout

Column

Vertical container; children render top-to-bottom.

ParamTypeDefaultValues
verticalArrangementstringTopTop, Center, Bottom, SpaceAround, SpaceBetween, SpaceEvenly
horizontalAlignmentstringStartStart, CenterHorizontally, End
spacingnumberabsentdp gap between children; overrides arrangement if set

Children: any widgets. Events/write-back: none.

{
  "type": "Column",
  "modifier": [
    { "name": "fillMaxWidth" },
    { "name": "paddingHorizontal", "value": "16" }
  ],
  "params": {
    "verticalArrangement": "Center",
    "horizontalAlignment": "CenterHorizontally"
  },
  "children": [
    { "type": "Text", "params": { "text": "Title" } },
    { "type": "Text", "params": { "text": "Subtitle" } }
  ]
}

Row

Horizontal container following layout direction.

ParamTypeDefaultValues
horizontalArrangementstringStartStart, End, Center, SpaceAround, SpaceBetween, SpaceEvenly
verticalAlignmentstringTopTop, CenterVertically, Bottom
spacingnumberabsentdp gap between children; overrides arrangement if set

Children: any widgets. Events/write-back: none.

{
  "type": "Row",
  "modifier": [{ "name": "fillMaxWidth" }],
  "params": {
    "horizontalArrangement": "SpaceBetween",
    "verticalAlignment": "CenterVertically"
  },
  "children": [
    { "type": "Text", "params": { "text": "$root.title" } },
    { "type": "Switch", "params": { "checked": "$root.enabled" } }
  ]
}

Box

Stack container; later children draw over earlier children.

ParamTypeDefaultValues
contentAlignmentstringTopStartTopStart, TopCenter, TopEnd, CenterStart, Center, CenterEnd, BottomStart, BottomCenter, BottomEnd

Children: any widgets. Events/write-back: none.

{
  "type": "Box",
  "modifier": [{ "name": "fillMaxWidth" }],
  "params": {
    "contentAlignment": "Center"
  },
  "children": [
    { "type": "Image", "params": { "url": "$root.heroUrl", "contentDescription": "Offer" } },
    { "type": "CircularProgress", "params": { "visible": "$root.loading" } }
  ]
}

Card

Semantic surface container.

ParamTypeDefaultMeaning
variantstringdefaultdefault, outlined, elevated, or host token
containerColorcolorsurface#RRGGBB / #AARRGGBB card fill

Children: any widgets. Event: envelope onClick (any widget). Write-back: none.

{
  "id": "offer-42",
  "type": "Card",
  "state": { "title": "Flat", "price": "25M" },
  "onClick": { "type": "navigate", "screen": "offer", "json": "$local" },
  "params": {
    "variant": "elevated"
  },
  "children": [
    {
      "type": "Column",
      "children": [
        { "type": "Text", "params": { "text": "$parent.title" } },
        { "type": "Text", "params": { "text": "$parent.price" } }
      ]
    }
  ]
}

Scaffold

Full-screen Material layout with optional topBar, bottomBar, and floatingActionButton slots. Use it as the root of a BduiScreenHost destination. Slot widgets are envelope fields (not params); they participate in $id.* lookup and patch like children.

ParamTypeDefaultValues
fabPositionstringEndEnd, Center
EnvelopeTypeDefaultMeaning
topBarwidgetabsentApp bar slot
bottomBarwidgetabsentBottom bar slot
floatingActionButtonwidgetabsentFAB slot

Children: content widgets, laid out inside the scaffold body with system padding. The bottomBar slot is padded above the system navigation bar (gesture handle / three-button nav); a background modifier on that slot still draws behind the inset. Events/write-back: none.

{
  "id": "root",
  "type": "Scaffold",
  "state": { "title": "Choose a city" },
  "topBar": {
    "type": "TopAppBar",
    "params": { "title": "$root.title" }
  },
  "floatingActionButton": {
    "type": "FloatingActionButton",
    "onClick": { "type": "popScreen", "result": { "title": "Astana" } },
    "children": [{ "type": "Text", "params": { "text": "★" } }]
  },
  "children": [
    { "type": "Text", "params": { "text": "Pick a city" } }
  ]
}

TopAppBar

App bar for a Scaffold topBar slot.

ParamTypeDefaultMeaning
titlestring""Title text
navigationIconstringsee belowback, close, or none
onNavigationClickactionpopScreenRuns when the navigation icon is pressed

Default navigationIcon is back on a pushed BDUI screen and none on an embedded root. Children: trailing actions. Write-back: none.

{
  "type": "TopAppBar",
  "params": {
    "title": "$root.title",
    "navigationIcon": "back",
    "onNavigationClick": { "type": "popScreen" }
  }
}

FloatingActionButton

Circular action button, typically in a Scaffold floatingActionButton slot.

ParamTypeDefaultMeaning
enabledboolean/pathtrueSuppresses click

Children: icon/label, usually Text. Event: envelope onClick. Write-back: none.

{
  "type": "FloatingActionButton",
  "onClick": { "type": "popScreen", "result": { "ok": true } },
  "children": [{ "type": "Text", "params": { "text": "+" } }]
}

LazyColumn

Scrollable virtualized vertical list. Each direct child is one item.

ParamTypeDefaultValues
verticalArrangementstringTopSame as Column
horizontalAlignmentstringStartSame as Column
spacingnumberabsentdp gap between items; overrides arrangement if set

Children: any widgets as items. Events/write-back: none.

{
  "type": "LazyColumn",
  "modifier": [{ "name": "fillMaxWidth" }],
  "children": [
    {
      "id": "offer-41",
      "type": "Card",
      "state": { "title": "First" },
      "children": [{ "type": "Text", "params": { "text": "$parent.title" } }]
    },
    {
      "id": "offer-42",
      "type": "Card",
      "state": { "title": "Second" },
      "children": [{ "type": "Text", "params": { "text": "$parent.title" } }]
    }
  ]
}

Dynamic items need stable ids for Compose keys, focus/scroll continuity, and streamed updates.

LazyRow

Scrollable virtualized horizontal list. Each direct child is one item.

ParamTypeDefaultValues
horizontalArrangementstringStartSame as Row
verticalAlignmentstringTopSame as Row
spacingnumberabsentdp gap between items; overrides arrangement if set

Children: any widgets as items. Events/write-back: none. Give items a fixed height when LazyRow sits inside LazyColumn.

{
  "type": "LazyRow",
  "modifier": [{ "name": "paddingHorizontal", "value": "16" }],
  "params": { "spacing": 12 },
  "children": [
    {
      "id": "promo-1",
      "type": "Card",
      "modifier": [{ "name": "width", "value": "220" }, { "name": "height", "value": "132" }],
      "children": [{ "type": "Text", "params": { "text": "Мебель" } }]
    }
  ]
}

Stepper

Container for multi-step flows: shows one child (a step) at a time and animates between them. Spec 11. Use it for a booking, a form or a wizard whose steps share state; moving between steps is a patch of one value, instead of a visibility flag per step.

ParamTypeDefaultMeaning
stepstring/path0The step to show: a zero-based index, or the id of a child. Bind it to state to move between steps
animatestringslideslide, fade or none. The height change between steps is animated too

Rules:

  • Only the selected child is composed. A step that is not shown keeps no UI state of its own, so keep values on an ancestor (the usual state on the flow's root) and bind the step's controls to it.
  • An index below zero shows the first step, one past the end shows the last, and a missing or unknown step shows the first.
  • There is no swiping: a flow has to validate before it moves on. Change step with a patch, usually in onValid of a validate.
  • When step is a state path, the system Back press moves to the previous step (a write of step - 1), except from the first step and from the last, which is the finished state.
{
  "type": "Column",
  "state": { "step": 0, "form": { "email": "" }, "errors": {} },
  "children": [
    {
      "type": "Stepper",
      "minSpec": 11,
      "params": { "step": "$id.signup.step" },
      "children": [
        { "type": "Column", "children": [
            { "type": "TextField", "params": { "value": "$id.signup.form.email", "error": "$id.signup.errors.email" } },
            { "type": "Button",
              "onClick": {
                "type": "validate",
                "errorsPath": "$id.signup/state/errors",
                "rules": [{ "path": "$id.signup.form.email", "key": "email", "required": true }],
                "onValid": { "type": "patch", "patch": [{ "op": "add", "path": "$id.signup/state/step", "value": 1 }] }
              },
              "children": [{ "type": "Text", "params": { "text": "Next" } }] }
        ] },
        { "type": "Text", "params": { "text": "Thanks!" } }
      ]
    }
  ]
}

Children: the steps. Events/write-back: none; Back writes step - 1 to the bound path.

Spacer

Empty fixed-size element.

ParamTypeDefaultMeaning
widthnumber/path0dp
heightnumber/path0dp

Children/events/write-back: none.

{ "type": "Spacer", "params": { "height": 16 } }

Negative/non-finite values become zero.

Divider

Decorative separator.

ParamTypeDefaultMeaning
thicknessnumber/path1dp
colorcolor/path$theme.colors.outline#RRGGBB or #AARRGGBB

Children/events/write-back: none. Excluded from accessibility semantics.

{ "type": "Divider", "params": { "thickness": 1, "color": "$theme.colors.outline" } }

Content

Calendar

Month grid for picking one date or a date range. Spec 8. Navigation and selection are local: no action or request is needed to change month or select a date.

ParamTypeDefaultMeaning
modestringsinglesingle or range
startstring/path""Selected date (yyyy-MM-dd). Write-back when a state path
endstring/path""Range end; write-back in range mode. An unset end is written as ""
monthstringstart/todayInitial month, yyyy-MM
min, maxstring/pathabsentEarliest/latest selectable date. min also accepts today
disabledarray/path[]Unavailable dates: "2026-10-15" or { "from", "to" } ranges
weekStartstringmondaymonday or sunday
localestringenen or ru month and weekday names
monthNamesarrayby locale12 custom month names
weekdayNamesarrayby locale7 custom names, Monday first
unavailableLabelstringUnavailableLegend text for unavailable dates
showLegendbooleantrueSelected / unavailable legend
compactbooleanfalseShorter day cells, for a calendar inside a small card such as the chat
todaystringsystem dateOverride today, for tests and demos
onChangeactionabsentAfter a selection is written. $event = { "start", "end" }
onMonthChangeactionabsentAfter month navigation. $event = { "month" }

Selectable means inside min..max and not in disabled. Unselectable dates ignore taps. In range mode the second tap completes the range; tapping before the start, or after a completed range, starts a new range; a range cannot span an unavailable date (the tap starts a new range instead). Availability always comes from disabled / min / max, which a tool or the backend fills; the widget never invents it.

{
  "type": "Calendar",
  "params": {
    "mode": "range",
    "start": "$root.search.depart",
    "end": "$root.search.ret",
    "min": "today",
    "disabled": "$root.availability.disabled",
    "onChange": { "type": "invokeTool", "tool": "get_time_slots", "arguments": { "date": "$root.search.depart" } }
  }
}

Children/events: none beyond onChange / onMonthChange.

Select

Dropdown that writes the chosen option back to its bound path. Spec 9. Use it for a choice among many options where a RadioGroup would be too long (a specialty, then the doctors of that specialty).

ParamTypeDefaultMeaning
optionsarray/path[]Plain strings, or { "value", "label"?, "subtitle"? }. Entries without a value are dropped
valuestring/path""Selected option value. Write-back when a state path. A value not in options shows the placeholder
labelstringabsentSmall caption above the selection
placeholderstringSelectShown while nothing valid is selected
errorstring/path""Validation message; non-empty outlines the field in the error color and shows the message
enabledbooleantrueAlso disabled while options is empty
onChangeactionabsentDispatched after the value is written, so $root paths already hold the new value
{
  "type": "Select",
  "params": {
    "label": "Specialty",
    "options": "$root.options.specialties",
    "value": "$root.booking.specialty",
    "onChange": { "type": "invokeTool", "tool": "get_doctors", "arguments": { "specialty": "$root.booking.specialty" } }
  }
}

Children: none.

Review

Read-only summary the user checks before committing. Spec 8. It renders structured data and has no business logic; confirm and cancel are ordinary Button widgets placed under it, so nothing runs until the user presses one.

ParamTypeMeaning
titlestring/pathHeading
descriptionstring/pathExplanatory text
sectionsarray/path[{ "title", "editStep"?, "editLabel"?, "rows": [{ "label", "value", "emphasis"? }], "items": [{ "title", "subtitle"?, "image"?, "trailing"? }] }]
breakdownarray/pathPrice lines [{ "label", "value", "kind"? }]; kind: "discount" is highlighted
totalobject/path{ "label", "value" }
warningstring/pathHighlighted notice
termsstring/pathFine print
onEditactionDispatched when a section's edit link is pressed. $event = that section's editStep

Bind every param to state ("sections": "$root.review.sections") so a tool or mapper can fill it from verified data. Values are shown as given, so format money and dates before putting them in state.

{
  "type": "Review",
  "params": {
    "title": "Review your booking",
    "sections": "$root.review.sections",
    "total": "$root.review.total",
    "onEdit": { "type": "patch", "patch": [{ "op": "add", "path": "$root/state/ui/step", "value": "form" }] }
  }
}

Children/write-back: none.

Chart

Data chart drawn by the SDK: line, area, bar, pie and donut. Use it for numbers the user asked to see (spending by category, price history, monthly totals). Spec 7.

ParamTypeDefaultMeaning
kindstringlineline, area, bar, pie, donut
labelsarray/pathline/area/bar: x-axis label per value
valuesarray/pathline/area/bar, one series: numbers, same length as labels
seriesarray/pathline/area/bar, several series: [{ "name", "values": [..], "color"? }]
slicesarray/pathpie/donut: [{ "label", "value", "color"? }]
valuePrefixstring/pathtext before every number
valueSuffixstring/pathtext after every number, e.g. " ₸"
heightnumber/path200dp, 80–600; line, area and bar only
centerTextstring/pathtotaldonut: text in the hole
centerLabelstring/pathdonut: caption under centerText
showLegendbooleanautotrue for pie, donut and multi-series charts
showValuesbooleanautobar: value above each bar; on up to 8 bars
smoothbooleantrueline/area: curved lines
animatebooleantruedraw-in animation

Colors default to the theme primary followed by a fixed palette; text and grid use theme colors. A flat values list, series and slices are interchangeable, so a chart still renders if the data arrives in the other shape. Missing or empty data shows No data.

Children/events/write-back: none.

{
  "type": "Chart",
  "params": {
    "kind": "donut",
    "valueSuffix": " ₸",
    "slices": [
      { "label": "Groceries", "value": 148200 },
      { "label": "Transport", "value": 62400 },
      { "label": "Shopping", "value": 214000 }
    ]
  }
}
{
  "type": "Chart",
  "params": { "kind": "area", "labels": ["Sep 1", "Sep 15", "Oct 1"], "values": [399990, 372000, 359990], "valueSuffix": " ₸" }
}

Text

ParamTypeDefaultMeaning
textstring/pathrequiredUnresolved path becomes empty
colorcolor/path$theme.colors.onSurfaceText color
fontSizenumber/pathvariant valuesp
fontWeightintegervariant value100–900
fontStylestringNormalNormal, Italic
variantstringbodyMediumTypography/component token
maxLinesintegerunlimitedPositive
overflowstringClipClip, Ellipsis
textAlignstringStartStart, Center, End

Children/events/write-back: none.

{
  "type": "Text",
  "params": {
    "text": "$root.offer.title",
    "variant": "titleLarge",
    "fontSize": 22,
    "maxLines": 2,
    "overflow": "Ellipsis"
  }
}

Escape a literal prefix: "text": "$$root is a path prefix".

Image

ParamTypeDefaultMeaning
contentDescriptionstring/path/nullrequirednull only for decorative image
urlstring/pathabsentRemote HTTP(S) image
assetNamestringabsentBundled Compose resource
contentScalestringFitFit, Crop, FillBounds, Inside
alphanumber/path1Clamped to 0..1
placeholderstringabsentBundled loading asset
errorAssetstringabsentBundled failure asset

Children/events/write-back: none.

{
  "type": "Image",
  "modifier": [
    { "name": "fillMaxWidth" },
    { "name": "height", "value": "240" }
  ],
  "params": {
    "url": "$root.offer.heroUrl",
    "assetName": "offer_placeholder",
    "contentDescription": "$root.offer.title",
    "contentScale": "Crop"
  }
}

url wins over assetName. Load failure displays errorAsset or empty space and logs; it is not an action failure.

Button

ParamTypeDefaultMeaning
variantstringprimaryprimary, secondary, tertiary, danger, or host token
loadingboolean/pathfalseDisplays progress and suppresses envelope onClick

Children: label/content, usually Text. Event: envelope onClick. Write-back: none.

{
  "type": "Button",
  "onClick": {
    "type": "http",
    "method": "POST",
    "url": "/v1/form",
    "body": { "fromState": "$root.form" },
    "success": { "apply": "none" }
  },
  "params": {
    "enabled": "$root.canSubmit",
    "loading": "$root.submitting",
    "variant": "primary"
  },
  "children": [{ "type": "Text", "params": { "text": "Submit" } }]
}

No envelope onClick means not clickable. Disabled or loading buttons do not dispatch.

CircularProgress

ParamTypeDefaultMeaning
progressnumber/pathabsent0..1; absent is indeterminate
strokeWidthnumber/paththeme valuedp
colorcolor/path$theme.colors.primaryIndicator color

Children/events/write-back: none.

{ "type": "CircularProgress", "params": { "visible": "$root.loading", "strokeWidth": 3 } }

LinearProgress

ParamTypeDefaultMeaning
progressnumber/pathabsent0..1; absent is indeterminate
colorcolor/path$theme.colors.primaryActive color
trackColorcolor/pathcomponent tokenTrack color

Children/events/write-back: none. Progress is clamped.

{ "type": "LinearProgress", "params": { "progress": "$root.upload.progress" } }

← State · Documentation · Next: Actions →

AppSana — экраны под задачу в приложениях, которые у вас уже есть.