> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getflowpilot.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Component reference

> Every FlowPilot component kind and the props it accepts.

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](/reference/conditions-and-expressions); 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).

| Group          | Props                                                                                                                  |
| -------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Visibility     | `isVisible` (bool), `visibility` (string), `opacity` (0 to 1), `disabled` (bool)                                       |
| Size           | `width`, `height`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight` (number px, `"NN%"`, or `"auto"`/`"fill"`)         |
| Padding        | `paddingVertical`, `paddingHorizontal`, `paddingTop/Bottom/Left/Right`, `paddingAdvanced` (bool)                       |
| Margin         | `marginTop`, `marginBottom`, `marginLeft`, `marginRight`                                                               |
| Corner radius  | `cornerRadius`, `cornerAdvanced` (bool), `cornerTopLeft/TopRight/BottomLeft/BottomRight`                               |
| Border         | `borderWidth`, `borderColor`, `borderStyle`, `borderOpacity`                                                           |
| Background     | `backgroundColor`, `fill`, `overflow`                                                                                  |
| Shadow         | `boxShadowColor`, `boxShadowOpacity`, `boxShadowX`, `boxShadowY`, `boxShadowBlur`, `boxShadowSpread`, `boxShadowInner` |
| Position       | `positionType` (`normal`/`relative`/`absolute`/`fixed`/`sticky`), `top`, `right`, `bottom`, `left`, `zIndex`           |
| Press feedback | `pressFeedback` object `{ style, scale, opacity, pressDuration, releaseDuration }`                                     |
| Attention      | `attention` object `{ effect, duration, delay, repeat, intensity }`                                                    |
| Animation      | `animations` (step timeline), plus legacy `animateOn`/`animOpacity`/`animScale`/...                                    |

Layout, styling, and animation props are covered in depth under [Properties](/editor/properties), [Layout and sizing](/editor/layout-and-sizing), and [Animations](/editor/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.

| Prop              | Type                                                 | Notes                                                                                                                                                    |
| ----------------- | ---------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `axis`            | `"vertical" \| "horizontal" \| "layered"`            | Also accepts legacy `direction`.                                                                                                                         |
| `spacing`         | number                                               | Gap between children. Also accepts legacy `gap`.                                                                                                         |
| `justify`         | string                                               | Main-axis distribution (Top/Center/Bottom/Fill Equally/Space Evenly/Space Around/Space Between, or Left/Center/Right by axis).                           |
| `align`           | string                                               | Cross-axis alignment.                                                                                                                                    |
| `wrap`            | string                                               | Wrap behavior.                                                                                                                                           |
| `scrollBehavior`  | `"no-scroll" \| "scroll"`                            | Scrolling along the stack's own axis.                                                                                                                    |
| `autoScroll`      | object                                               | Marquee loop for a **horizontal** stack: `{ enabled, direction?: "left" \| "right", speed?: px/sec }`. See [Auto-scroll](#auto-scroll-carousel-marquee). |
| `staggerChildren` | bool                                                 | Stagger children's appear animations.                                                                                                                    |
| `staggerInterval` | number                                               | Ms between each child (default 80).                                                                                                                      |
| `staggerOrder`    | `"natural" \| "reverse" \| "center-out" \| "random"` | Stagger order.                                                                                                                                           |
| `staggerHaptic`   | `"none" \| "tick" \| "ramp"`                         | Per-child haptic.                                                                                                                                        |

Supports the `onAppear` and `onPress` interactions.

### Auto-scroll (Carousel marquee)

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.

```json theme={null}
{
  "type": "stack",
  "props": {
    "axis": "horizontal",
    "scrollBehavior": "scroll",
    "spacing": 12,
    "autoScroll": { "enabled": true, "direction": "left", "speed": 40 }
  }
}
```

| Field       | Type                | Default  | Notes                                                                                                                                     |
| ----------- | ------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled`   | bool                | —        | Omit the whole object (or set `false`) for a normal swipeable carousel.                                                                   |
| `direction` | `"left" \| "right"` | `"left"` | Which way the content travels. `"left"` means cards drift leftward and new ones enter from the right.                                     |
| `speed`     | number              | `40`     | Drift speed in **px/second**. The cycle length is derived from it, so adding a slide lengthens the loop instead of speeding the drift up. |

<Note>
  **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.
</Note>

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.

| Prop            | Type   | Notes                                                                                                                                        |
| --------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `text`          | string | The content. Supports `{{variable}}` interpolation.                                                                                          |
| `color`         | string | Text color.                                                                                                                                  |
| `fontSize`      | number | Point size (8 to 120).                                                                                                                       |
| `fontWeight`    | string | `"100"` to `"900"` or named weight.                                                                                                          |
| `fontFamily`    | string | System, custom, or a Google font.                                                                                                            |
| `textAlign`     | string | Left/Center/Right.                                                                                                                           |
| `lineHeight`    | number | Line height.                                                                                                                                 |
| `letterSpacing` | number | Tracking.                                                                                                                                    |
| `textCase`      | string | Case transform.                                                                                                                              |
| `maxLines`      | number | Truncate after N lines.                                                                                                                      |
| `textEffect`    | object | `{ type, speed, delay, duration, cursor, cursorChar, haptic }`. Types: `typewriter`, `typewriterWord`, `fadePerLine`, `countUp`, `scramble`. |
| `textRotation`  | object | Word cycling: `{ enabled, values[], interval, transition, transitionDuration, loop, pauseOnLast }`.                                          |
| `countdown`     | object | Turns the label into a ticking clock. See below.                                                                                             |

### 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.

| Field             | Type      | Notes                                                                                                     |
| ----------------- | --------- | --------------------------------------------------------------------------------------------------------- |
| `enabled`         | boolean   | Turns the clock on.                                                                                       |
| `durationSeconds` | number    | Time on the clock, e.g. `10800` for 3 hours.                                                              |
| `format`          | string    | `h:mm:ss` (default), `hh:mm:ss`, `m:ss`, `mm:ss`, `ss`, `hh`, `mm`, or `compact` (`"2h 59m"`).            |
| `timerId`         | string    | Shared clock id. Defaults to the component's own id.                                                      |
| `startMode`       | string    | `oncePerFlow` (default) keeps counting across screens; `onAppear` restarts every time the screen appears. |
| `expiredText`     | string    | Shown at zero. Defaults to the zero-formatted string.                                                     |
| `onComplete`      | action\[] | Fired once when the clock reaches zero.                                                                   |
| `milestones`      | object\[] | `[{ id?, atSecondsRemaining, actions }]` — fired once each as the clock passes a mark.                    |

**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](/reference/actions-reference) instead, which is how you react to it:

```json theme={null}
{
  "enabled": true,
  "durationSeconds": 10800,
  "format": "h:mm:ss",
  "milestones": [
    {
      "atSecondsRemaining": 30,
      "actions": [{ "kind": "setVariable", "variableKey": "urgent", "value": true }]
    }
  ],
  "onComplete": [
    { "kind": "setVariable", "variableKey": "offer_expired", "value": true },
    { "kind": "trackEvent", "eventKey": "offer_expired" },
    { "kind": "custom", "actionKey": "offer_expired", "params": { "offerId": "yearly_intro" } }
  ]
}
```

* `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](/reference/actions-reference#custom).
* `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.

| Prop        | Type   | Notes                                                                                  |
| ----------- | ------ | -------------------------------------------------------------------------------------- |
| `src`       | string | Full `http(s)://` URL, a `data:` URL, or a relative path joined to the media base URL. |
| `alt`       | string | Alt text.                                                                              |
| `fit`       | string | `cover` / `contain` / `fill` / `tile`.                                                 |
| `tintColor` | string | Optional tint.                                                                         |

## `button`

A tappable container. Shares the stack style surface, so it accepts the stack layout and box props plus the text props below.

| Prop                                                | Type                                                   | Notes                                                                                                                 |
| --------------------------------------------------- | ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- |
| `text`                                              | string                                                 | Button label.                                                                                                         |
| `variant`                                           | `"primary" \| "secondary" \| "ghost" \| "destructive"` | Resolves default colors against `globalStyles.colors`. Per-prop overrides win.                                        |
| `color`                                             | string                                                 | Text color (overrides variant).                                                                                       |
| `fontSize`, `fontWeight`, `fontFamily`, `textAlign` |                                                        | Label typography.                                                                                                     |
| `iconSize`                                          | number                                                 | Size of an icon child.                                                                                                |
| layout/box props                                    |                                                        | `axis`, `spacing`, `justify`, `align`, padding, `backgroundColor`, border, `cornerRadius`, shadow, `width`, `height`. |

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.

| Prop               | Type                                                                                | Notes                                                                 |
| ------------------ | ----------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| `inputType`        | `text` / `email` / `number` / `password` / `url` / `phone` / `multiline` / `search` | Maps to the keyboard type. Also accepts legacy `type`.                |
| `placeholder`      | string                                                                              | Placeholder text.                                                     |
| `placeholderColor` | string                                                                              | Placeholder color.                                                    |
| `variableKey`      | string                                                                              | The variable this field reads on appear and writes on change.         |
| `maxLength`        | number                                                                              | Character limit.                                                      |
| `rows`             | number                                                                              | Visible rows for `multiline`.                                         |
| `returnKeyType`    | `done` / `next` / `go` / `search` / `send`                                          | Return key label.                                                     |
| `validation`       | object                                                                              | `{ required, minLength, maxLength, pattern, patternMessage }`.        |
| `autoFocus`        | bool                                                                                | Focus the field and raise the keyboard as soon as the screen appears. |
| `focusLock`        | bool                                                                                | Keep the keyboard up. Implies `autoFocus`.                            |

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.

<Warning>
  **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.
</Warning>

<Note>
  **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.
</Note>

## `toggle`

A switch bound to a boolean variable.

| Prop            | Type   | Notes                                        |
| --------------- | ------ | -------------------------------------------- |
| `value`         | bool   | Initial value (bound variable wins on load). |
| `variableKey`   | string | The boolean variable to read/write.          |
| `activeColor`   | string | On color.                                    |
| `inactiveColor` | string | Off color.                                   |
| `label`         | string | Optional label.                              |

Interaction: `onChange`.

<Note>
  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.
</Note>

## `progress`

A linear progress bar.

| Prop                | Type                 | Notes                                                                 |
| ------------------- | -------------------- | --------------------------------------------------------------------- |
| `mode`              | `"auto" \| "custom"` | `auto` derives the value from screen position; `custom` uses `value`. |
| `value`             | number (0 to 1)      | Progress when `mode` is `custom`.                                     |
| `color`             | string               | Fill color.                                                           |
| `trackColor`        | string               | Track color.                                                          |
| `animateProgress`   | bool                 | Animate value changes.                                                |
| `animationDuration` | number               | Ms.                                                                   |
| `animationCurve`    | string               | Easing.                                                               |

`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`.

| Prop                | Type                                              | Notes                                                                 |
| ------------------- | ------------------------------------------------- | --------------------------------------------------------------------- |
| `mode`              | `"determinate" \| "indeterminate"`                | Default `determinate`.                                                |
| `value`             | number (0 to 1)                                   | Only meaningful when determinate.                                     |
| `size`              | number                                            | Outer diameter. Default 96.                                           |
| `strokeWidth`       | number                                            | Ring thickness. Default 8.                                            |
| `color`             | string                                            | Arc color. Default `#4F46E5`.                                         |
| `trackColor`        | string                                            | Background ring. Default `#E5E7EB`.                                   |
| `animateOnAppear`   | bool                                              | Animate value changes. Default true.                                  |
| `animationDuration` | number                                            | Ms. Default 800.                                                      |
| `animationCurve`    | `linear` / `ease-in` / `ease-out` / `ease-in-out` |                                                                       |
| `revealOnAppear`    | bool                                              | Scripted reveal: animate 0 to value on appear, ignoring the variable. |
| `children`          | `ComponentNode[]`                                 | Centered slot (usually one text or icon).                             |

## `icon`

A vector icon (Lucide).

| Prop          | Type   | Notes                                                                       |
| ------------- | ------ | --------------------------------------------------------------------------- |
| `iconName`    | string | Icon name. Accepts a conditional value so the glyph can be variable-driven. |
| `size`        | number | Glyph size.                                                                 |
| `color`       | string | Glyph color.                                                                |
| `strokeWidth` | number | Stroke width.                                                               |

## `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.

| Prop                 | Type   | Notes                                                                                                                                 |
| -------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------- |
| `min`                | number | Range minimum. Default 0.                                                                                                             |
| `max`                | number | Range maximum. Default 100.                                                                                                           |
| `step`               | number | Increment. Default 1.                                                                                                                 |
| `value`              | number | Initial value (bound variable wins on load).                                                                                          |
| `variableKey`        | string | Two-way binding (read on appear, written on change).                                                                                  |
| `trackColor`         | string | Unfilled track (token or hex). Default `#E5E7EB`.                                                                                     |
| `fillColor`          | string | Filled portion (token or hex). Default `#4F46E5`.                                                                                     |
| `fillColorEnd`       | string | When set, the fill becomes a horizontal gradient from `fillColor` (left) to `fillColorEnd` (at the thumb). Token or hex.              |
| `thumbColor`         | string | Knob (token or hex). Default `#4F46E5`.                                                                                               |
| `trackHeight`        | number | Track and fill thickness. Default 6.                                                                                                  |
| `thumbStyle`         | string | `"circle"` (default) or `"pill"`. `"pill"` is a vertical capsule thumb that overhangs the track (the modern CalAI / onboarding look). |
| `thumbSize`          | number | Circle diameter / pill width. Default 18 for `"circle"`, 28 for `"pill"`.                                                             |
| `showValueLabel`     | bool   | Show the current value.                                                                                                               |
| `valueFormat`        | string | Display template, `"{{value}}"` is substituted (for example `"{{value}} kg"`).                                                        |
| `valueLabelPosition` | string | `"inline"` (default) or `"top"`. `"top"` renders a large value readout centered above the track.                                      |
| `valueLabelSize`     | number | Readout font size. Default 14 inline, 40 on top.                                                                                      |
| `valueLabelColor`    | string | Readout colour (token or hex). Default secondary gray inline, the fill colour when on top.                                            |

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.

| Prop              | Type             | Notes                                       |
| ----------------- | ---------------- | ------------------------------------------- |
| `src`             | string           | Animation URL. Resolved like `image` `src`. |
| `autoplay`        | bool             | Play on appear. Default true.               |
| `loop`            | bool             | Loop. Default true.                         |
| `speed`           | number           | Playback multiplier. Default 1.             |
| `width`, `height` | number or string | Size.                                       |

## `comparisonChart`

A "you with us vs you without us" comparison curve.

| Prop                | Type             | Notes                                                                                               |
| ------------------- | ---------------- | --------------------------------------------------------------------------------------------------- |
| `series`            | array            | `{ label, color, points: [{x, y}], style?, showArea?, showEndDot?, animate? }`. Capped at 5 series. |
| `xLabels`           | `{ start, end }` | Axis end labels.                                                                                    |
| `yLabel`            | string           | Y-axis label.                                                                                       |
| `markers`           | `[{ x, label }]` | Vertical annotations.                                                                               |
| `animateOnAppear`   | bool             | Draw curves on appear. Default true.                                                                |
| `animationDuration` | number           | Ms. Default 900.                                                                                    |
| `staggerSeries`     | bool             | Reveal series in sequence. Default false.                                                           |
| `staggerDelay`      | number           | Ms between series. Default 250.                                                                     |
| `legend`            | bool             | Show per-series legend. Default false.                                                              |
| `height`            | number or string | Chart height; width fills the parent.                                                               |

## `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.

| Prop                           | Type   | Notes                                                                                                                                                                                                                                                                                                                                                   |
| ------------------------------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `mode`                         | string | `"wheel"` (default) or `"date"`.                                                                                                                                                                                                                                                                                                                        |
| `columns`                      | array  | Wheel mode. One entry per column: `{ header?, variableKey, unit?, defaultValue?, width? }` plus exactly one source: a numeric range (`min`, `max`, `step`) or an `options` list (`[{ label, value }]`). The written value is the raw number / option value; `unit` is a display-only suffix ("5 ft"). `width` is a flex weight for proportional widths. |
| `variableKey`                  | string | Date mode: the single variable that receives the ISO `"YYYY-MM-DD"` string.                                                                                                                                                                                                                                                                             |
| `minDate`, `maxDate`           | string | Date mode bounds (ISO). Default `1900-01-01` / today.                                                                                                                                                                                                                                                                                                   |
| `dateOrder`                    | string | Date mode column order: `"mdy"` (default), `"dmy"`, `"ymd"`.                                                                                                                                                                                                                                                                                            |
| `monthFormat`                  | string | Date mode month label: `"short"` (default, `Jan`), `"long"` (`January`), `"number"` (`1`).                                                                                                                                                                                                                                                              |
| `defaultValue`                 | string | Date mode initial ISO date (bound variable wins on load).                                                                                                                                                                                                                                                                                               |
| `visibleRows`                  | number | Odd row count including the centered one. Default 5.                                                                                                                                                                                                                                                                                                    |
| `itemHeight`                   | number | Row height in px. Default 40.                                                                                                                                                                                                                                                                                                                           |
| `selectionStyle`               | string | Center highlight: `"pill"` (default), `"lines"`, `"none"`.                                                                                                                                                                                                                                                                                              |
| `selectionColor`               | string | Pill fill / hairline colour (token or hex).                                                                                                                                                                                                                                                                                                             |
| `textColor`                    | string | Unselected rows (token or hex). Default `token:textSecondary`.                                                                                                                                                                                                                                                                                          |
| `selectedTextColor`            | string | Centered row (token or hex). Default `token:textPrimary`.                                                                                                                                                                                                                                                                                               |
| `headerColor`                  | string | Column header (token or hex). Default `token:textPrimary`.                                                                                                                                                                                                                                                                                              |
| `fontSize`, `selectedFontSize` | number | Unselected / centered row font. Defaults 20 / 22.                                                                                                                                                                                                                                                                                                       |
| `haptics`                      | bool   | Tick on each detent (device only). Default true.                                                                                                                                                                                                                                                                                                        |
| `loop`                         | bool   | Infinite wrap. Default false.                                                                                                                                                                                                                                                                                                                           |
| `unitToggle`                   | object | Optional Imperial/Metric switch (see below). When present it replaces `columns`/`mode`.                                                                                                                                                                                                                                                                 |

### 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.

| Field               | Type                        | Notes                                                                                                                                                                                                                                                                              |
| ------------------- | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `toggleStyle`       | `"segmented"` \| `"switch"` | Control look. `"segmented"` (default) is the iOS Imperial\|Metric pill; `"switch"` is a label on each side of an iOS toggle (`Imperial ◯─ Metric`), with the active side emphasised. `"switch"` needs exactly two `options` — with any other count it falls back to `"segmented"`. |
| `options`           | array                       | One entry per system: `{ key, label, columns: [PickerColumn] }`. Each column carries a `unit`.                                                                                                                                                                                     |
| `canonicalSystem`   | string                      | Option key whose columns define the normalized output variables/units. Default: the option keyed `"metric"`, else the last option.                                                                                                                                                 |
| `systemVariableKey` | string                      | Receives the active system key (`"imperial"` / `"metric"`).                                                                                                                                                                                                                        |
| `default`           | string                      | Initial system key. Default: `canonicalSystem`, else the first option.                                                                                                                                                                                                             |

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.

| Prop                                 | Type   | Notes                                                                                                                                           |
| ------------------------------------ | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `orientation`                        | string | `"horizontal"` (default) or `"vertical"`. Horizontal = ticks along a row (the weight scale); vertical = ticks down a column (the height scale). |
| `min`                                | number | Scale start. Default 0.                                                                                                                         |
| `max`                                | number | Scale end. Default 100.                                                                                                                         |
| `step`                               | number | Value between adjacent ticks and the snap increment. Default 1.                                                                                 |
| `value`                              | number | Initial value (bound variable wins on load).                                                                                                    |
| `variableKey`                        | string | Two-way binding (read on appear, written on each detent).                                                                                       |
| `unit`                               | string | Dimension/suffix key for conversion and the `"plain"` readout suffix (`kg`, `in`, …).                                                           |
| `majorEvery`                         | number | Every Nth tick is a long/major tick. Default 5.                                                                                                 |
| `tickSpacing`                        | number | Pixels between adjacent ticks. Default 12.                                                                                                      |
| `tickThickness`                      | number | Tick line thickness. Default 2.                                                                                                                 |
| `minorTickLength`, `majorTickLength` | number | Tick lengths. Defaults 16 / 28.                                                                                                                 |
| `tickColor`                          | string | Minor ticks (token or hex). Default `token:textTertiary`.                                                                                       |
| `majorTickColor`                     | string | Major ticks (token or hex). Default `token:textSecondary`.                                                                                      |
| `indicatorColor`                     | string | Center selection line (token or hex). Default `token:primary`.                                                                                  |
| `indicatorThickness`                 | number | Indicator line thickness. Default 3.                                                                                                            |
| `showValueLabel`                     | bool   | Show the large value readout. Default true.                                                                                                     |
| `valueFormat`                        | string | `"plain"` → `value` + unit via `valueTemplate`; `"feetInches"` → total inches shown as `6'1"` (length only). Default `"plain"`.                 |
| `valueTemplate`                      | string | `"plain"` display template, `"{{value}}"` substituted (for example `"{{value}} kg"`).                                                           |
| `valueColor`                         | string | Readout colour (token or hex). Default `token:textPrimary`.                                                                                     |
| `valueFontSize`                      | number | Readout font size. Default 48.                                                                                                                  |
| `unitToggle`                         | object | Optional Imperial/Metric switch (see below). When present it replaces the top-level scale.                                                      |

### 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.

| Field               | Type                        | Notes                                                                                                                                                                                       |
| ------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `toggleStyle`       | `"switch"` \| `"segmented"` | Control look. `"switch"` (default) is a label on each side of an iOS toggle (`Imperial ◯─ Metric`); `"segmented"` is the iOS Imperial\|Metric pill. `"switch"` needs exactly two `options`. |
| `options`           | array                       | One entry per system: `{ key, label, track }`. The `track` is `{ variableKey, unit, min, max, step, defaultValue, valueFormat?, valueTemplate?, majorEvery? }`.                             |
| `canonicalSystem`   | string                      | Option key whose track defines the normalized output variable/unit. Default: the option keyed `"metric"`, else the last option.                                                             |
| `systemVariableKey` | string                      | Receives the active system key (`"imperial"` / `"metric"`).                                                                                                                                 |
| `default`           | string                      | Initial system key. Default: `canonicalSystem`, else the first option.                                                                                                                      |

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`):

| Prop              | Type                                        | Notes                                                                        |
| ----------------- | ------------------------------------------- | ---------------------------------------------------------------------------- |
| `customComponent` | `{ key: string; version: number }`          | Reference to the definition (`CustomComponentRef`). `version` defaults to 1. |
| `inputs`          | `Record<string, CustomComponentInputValue>` | Per input: `{ source: "value", value }` or `{ source: "bind", variable }`.   |
| `width`           | size mode or config                         | `"content"` / `"fill"` / number, or `{ mode, min?, max? }`.                  |
| `height`          | size mode or config                         | Same shape as `width`.                                                       |

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](/ios-sdk/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](/reference/schema-versions).
* Any prop the renderers do not read is ignored, not an error.

## Related pages

* [Components (editor)](/editor/components)
* [Properties panel](/editor/properties)
* [Actions reference](/reference/actions-reference)
