Skip to main content
There are 15 component kinds. Every component is a ComponentNode with an id, a type, and an untyped props bag. This page lists each kind and the props the renderers read. Props are stored as Record<string, any>. The names below are the keys the SDK renderers read (ComponentProps in both the iOS and Expo SDKs) plus the intended shapes documented in the schema. A prop can be a plain value or a dynamic (conditional) value; string props also support {{variable}} interpolation.

Universal props

These apply to every visible component (a few do not apply to screenRoot or custom, noted in those sections). Layout, styling, and animation props are covered in depth under Properties, Layout and sizing, and Animations. The sections below list the props that are specific to each kind.

screenRoot

The implicit root container of a screen, rendered as the “Root Stack”. Treated as a stack; it exposes stack layout props (axis, spacing, align, justify) and spacing only. It is not added from the palette.

stack

A flex container. The primary layout primitive. Children render along an axis. Supports the onAppear and onPress interactions. Set autoScroll on a horizontal stack and its children drift in a seamless, endless loop instead of being swiped — the motion behind the Carousel block’s Scroll automatically toggle. The children are repeated as many times as it takes to fill the screen, so the row never trails a gap, even with two slides.
Auto-scroll is display-only. It replaces manual scrolling — the row ignores touch on every platform, because a drifting card is not something a user can reliably tap. Put anything interactive outside the carousel.Keep scrollBehavior: "scroll" set alongside it. An older SDK that predates autoScroll ignores it and renders a plain swipeable carousel, rather than a motionless clipped row.
Ignored on vertical and layered stacks. Honors the OS Reduce Motion setting by holding the row still. In the editor the row only drifts in preview — the editing canvas keeps it still so you can still drop elements into the slides.

text

A text label.

Countdown

Setting countdown makes a text node render its own clock instead of props.text. It is not a separate component kind — the same idea as autoProgress on progress — so it styles like any other label and needs no special SDK setup. A countdown never survives a session. The deadline is held in memory for as long as the flow is presented and is never written to disk, so relaunching the app always starts from the full duration. Use it for urgency, not for entitlement — anything a user could gain by force-quitting belongs on your server. Wiring it up. A countdown does not expose a ticking variable (a value changing every second would re-render everything bound to it). It emits ordinary actions instead, which is how you react to it:
  • setVariable flips a flag; any property elsewhere can then be a conditional value that reads it (swap a price, hide a card, disable a button).
  • trackEvent records it in analytics with no app-side code.
  • custom calls into your app — see custom actions.
  • goNext, navigate, closeFlow, haptic and the rest all work too.
Every hook fires at most once per timer per session. If the app spends time in the background and comes back past the deadline, onComplete fires on the first tick back; of any milestones crossed while away, only the last one fires (so you don’t get a burst of stale nudges on resume). Several labels, one clock. Give multiple text nodes the same timerId and they share a single deadline, each rendering the unit its format asks for. That is how the boxed 03 : 12 : 45 layout is built — three cells, formats hh / mm / ss — with no extra components. The first node to register stamps the clock and owns its actions, so declare the emit hooks on one of them.

image

A remote or bundled image.

button

A tappable container. Shares the stack style surface, so it accepts the stack layout and box props plus the text props below. The main interaction is onPress. A Back Button is a button with a goBack action; a Close Button is a button with a closeFlow action.

input

A text field. Reads and writes a bound variable. Interactions: onChange, onFocus, onBlur (binding to the variable is implicit via variableKey).

Focus behavior

In the editor these are the Focus on open and Keep keyboard open toggles on an input, in both Simple and Advanced mode. autoFocus opens the screen with the field focused and the keyboard up. If more than one input on a screen sets it, the first in tree order wins and the rest are ignored. focusLock additionally suppresses every way the user could dismiss the keyboard — tapping outside, swiping the content, and the return key — until the flow navigates to another screen. Use it for a screen where typing is the screen.
Put the continue button in the footer zone on a locked screen. The footer rises above the keyboard, so it stays tappable. An in-screen button on a scrollBehavior: "no-scroll" screen can end up buried under a keyboard the user cannot dismiss, which dead-ends the flow.
The lock is best-effort, and how it holds differs by path. Tapping outside and swiping to dismiss are refused outright, so nothing blinks. The return key is refused outright on Expo, but on iOS it blinks (SwiftUI gives no way to stop a field resigning on submit, so the SDK re-focuses instead). The same blink applies wherever the OS owns the dismissal and hides the keyboard regardless: iPad’s hide-keyboard key, an attached hardware keyboard, and Android’s back button.Both props are honored for inputs in the screen layout only — an input placed in a persistent zone ignores them, the same boundary required gating draws.

toggle

A switch bound to a boolean variable. Interaction: onChange.
There is no checkbox component kind. A checkbox is composed as a Block (a tappable stack with an icon whose glyph swaps via a conditional value). Old checkbox nodes are migrated into that shape on load.

progress

A linear progress bar. progress is not in the component palette; it is added via the Progress Bar block or in a zone.

ringProgress

A circular progress ring. A separate primitive from progress.

icon

A vector icon (Lucide).

slider

A numeric range control with a draggable thumb. Binds like input: it reads its variable on appear and writes the value live on every drag. The styling props (trackHeight, fillColorEnd, thumbStyle, thumbSize, valueLabelPosition, valueLabelSize, valueLabelColor) are optional and additive; their defaults preserve the original look. Interaction: onChange. Curated presets (Hours, Percentage, Rating, Amount) live in the “Sliders” subgroup of the “Pickers” category of the block library; each is the same slider pre-styled with a gradient fill, a pill thumb, and a large top readout, bound to an auto-managed number variable.

lottie

A Lottie animation.

comparisonChart

A “you with us vs you without us” comparison curve.

picker

A scroll-snapping value wheel (the iOS UIPickerView look). One primitive that holds one or more columns, so it covers the standalone number/age wheel (1 column), the side-by-side height/weight picker (2-3 columns), and the date-of-birth picker (mode: "date"). Each column binds like slider/input: it reads its variable on appear and writes the selected value back on every detent.

Imperial / Metric unit toggle

Set unitToggle to put an Imperial/Metric control above the wheel — a segmented pill or, via toggleStyle: "switch", a label on each side of an iOS toggle. Each “system” carries its own columns; toggling converts the value (150 lb → 68 kg) and the picker always writes a canonical normalized variable (kg / cm) regardless of the chosen system, so your logic stays unit-agnostic. Conversion uses a built-in units table — mass (base kg): kg g lb st; length (base cm): cm m mm in ft — keyed off each column’s unit. Toggling preserves the value per dimension and redistributes it into the new system’s columns (the ft+in split included). A unit not in the table means no conversion for that dimension (pure column swap). Interaction: onChange. Curated presets (Age, Height, Weight, Height & Weight, Date of birth) live in the “Pickers” category of the block library; Weight, Height, and Height & Weight ship with the unit toggle on by default.

ruler

A tick-mark measuring scale that drags under a fixed center indicator (the inverse of slider’s drag-the-thumb). It picks a single continuous numeric value, snapped to step, and shows a big live readout — the “What is your height? / weight?” onboarding scale. Binds like slider: it reads its variable on appear and writes the snapped value back on every detent.

Imperial / Metric unit toggle

Set unitToggle to add an Imperial/Metric control below the scale — a "switch" (default for rulers) or a "segmented" pill. Each “system” carries exactly one track (a ruler is a single continuous scale, not multiple columns). Toggling converts the value and the ruler always writes a canonical normalized variable (kg / cm) regardless of the chosen system, so your logic stays unit-agnostic. Conversion uses the same built-in units table as picker — mass (base kg): kg g lb st; length (base cm): cm m mm in ft — keyed off the track’s unit. Because a ruler is a single value, conversion is a single scalar (no ft+in column split); a length track can set valueFormat: "feetInches" to display its inches scale as 6'1". Interaction: onChange. Curated presets (Weight, Height, Value) live in the “Scales” subgroup of the “Pickers” category; Weight and Height ship with the unit toggle on by default.

custom

An app-scoped custom component placed by reference. Custom components render as placeholder shells in the editor and resolve to your registered native view on iOS. They have limited layout props (no background, border, shadow, padding, typography, position, z-index). Instance props (CustomComponentInstanceProps): Custom components emit outputs (events) that you wire to actions in the editor. The native side and the editor agree on a key + version + input keys + output keys contract. See Custom components.

Notes

  • Components removed from the schema (spacer, divider, card, chip, carousel, video, checkbox, and the old placeholder chart) are rewritten or stripped by migrations on load. See Schema versions.
  • Any prop the renderers do not read is ignored, not an error.