Operator UI
Last updated on May 21, 2026
The operator UI is a per-phase component set the runtime renders to the operator. Inputs collect data and block the phase until the operator submits, while displays stream values from Python in real time. The same declaration renders identically in CLI and on a factory Station, so what you build on your laptop is what an operator sees on the floor.
Anatomy
A phase declares its UI under a ui block, and that block holds a list of components plus a few top-level fields.
main:
- name: Scan Unit
python: phases.scan_unit
ui:
components:
- key: serial_number
type: text_input
label: "Serial Number"
bind: unit.serial_number
- key: live_voltage
type: text
label: "Live Voltage"
size: xl| Field | Description |
|---|---|
components | List of UI components. |
requires_input | Force a Continue button even when no input components exist. Auto-detected from input components. |
Component fields
Every component supports the base fields below, so you can lean on them before reaching for type-specific knobs.
| Field | Description |
|---|---|
key | Unique identifier. Required. Used as the Python attribute on ui and as the form field name. |
type | Component type. See catalog. |
label | Label rendered above the component. |
description | Helper text rendered below the label. |
required | Whether the operator must provide a value. Inputs only. Defaults to true. |
default_value | Initial value. Type matches the component's value type. |
bind | Bind the value to measurements.<key> or unit.<field>. Inputs only. |
Type-specific fields are documented in each component section below.
Catalog
Inputs block phase completion until the operator submits a value that passes validation, while displays update in real time when Python assigns ui.<key> = value.
| Type | Category | Value type |
|---|---|---|
text_input | Input | string |
textarea | Input | string |
number_input | Input | number |
slider | Input | number |
switch | Input | boolean |
radio | Input | string |
select | Input | string |
checklist | Input | string[] |
multiselect | Input | string[] |
image_choice | Input | string |
image_checklist | Input | string[] |
text | Display | string |
image | Display | string (URL or data URI) |
progress | Display | number |
Inputs
text_input
A single-line text field with optional validation. The value type is string.
| Field | Description |
|---|---|
placeholder | Hint shown when empty. |
min_length | Minimum character count. |
max_length | Maximum character count. |
pattern | Regex string the value must match. |
prefix | Inline label rendered before the input (e.g. SN-). |
suffix | Inline label rendered after the input (e.g. mm). |
trim | Trim leading/trailing whitespace before submit. Defaults to true. |
- key: serial_number
type: text_input
label: "Serial Number"
pattern: "^SN-[0-9]{8}$"
required: truetextarea
A multi-line text field with the same constraints as text_input plus a rows field for visible height.
| Field | Description |
|---|---|
placeholder | Hint shown when empty. |
min_length | Minimum character count. |
max_length | Maximum character count. |
pattern | Regex string the value must match. |
rows | Visible row count. |
trim | Trim leading/trailing whitespace. Defaults to true. |
- key: notes
type: textarea
label: "Operator Notes"
rows: 4
max_length: 500
required: falsenumber_input
A numeric field with stepper buttons. The value type is number.
| Field | Description |
|---|---|
min | Minimum value. |
max | Maximum value. |
step | Increment for the stepper buttons. Defaults to 1. Drives decimal precision. |
placeholder | Hint shown when empty. |
prefix | Inline label rendered before the input. |
suffix | Inline label rendered after the input (e.g. V, mm). |
The operator must enter a number between min and max inclusive and a multiple of step, because the field validates on submit.
- key: target_voltage
type: number_input
label: "Target Voltage"
min: 0
max: 12
step: 0.1
suffix: "V"slider
A numeric input with a draggable handle and visible min/max labels. The value type is number.
| Field | Description |
|---|---|
min | Minimum value. Defaults to 0. |
max | Maximum value. Defaults to 100. |
step | Increment. Defaults to 1. |
- key: torque
type: slider
label: "Torque"
min: 0
max: 10
step: 0.5switch
A boolean toggle. The value type is boolean, and when required: true the operator must explicitly flip the switch because the initial unset state fails validation.
| Field | Description |
|---|---|
default_value | true or false. |
options | Optional [{label, value}, {label, value}] to override the on/off labels (defaults to "Yes"/"No"). |
- key: cover_closed
type: switch
label: "Cover Closed"
required: trueradio
A single selection from a vertical list. The value type is string, and it requires options.
| Field | Description |
|---|---|
options | List of {label, value} pairs. |
- key: outcome
type: radio
label: "Visual Inspection"
required: true
options:
- { label: "Pass", value: pass }
- { label: "Cosmetic defect", value: cosmetic }
- { label: "Fail", value: fail }select
A single selection from a dropdown. The value type is string, and it requires options.
| Field | Description |
|---|---|
options | List of {label, value} pairs. |
placeholder | Text shown before a value is selected. Defaults to "Select...". |
- key: line
type: select
label: "Production Line"
placeholder: "Choose a line"
options:
- { label: "Line A", value: a }
- { label: "Line B", value: b }checklist
Multiple selections rendered as checkboxes. The value type is string[], and it requires options.
| Field | Description |
|---|---|
options | List of {label, value} pairs. |
When required: true, the operator must select at least one item.
- key: pre_flight
type: checklist
label: "Pre-flight Checks"
required: true
options:
- { label: "Power supply connected", value: power }
- { label: "USB cable seated", value: usb }
- { label: "Antenna installed", value: antenna }multiselect
Multiple selections from a dropdown. The value type is string[], it requires options, and you reach for it over checklist when you have many options or limited vertical space.
| Field | Description |
|---|---|
options | List of {label, value} pairs. |
placeholder | Text shown before any value is selected. |
- key: defects
type: multiselect
label: "Observed Defects"
required: false
options:
- { label: "Scratch", value: scratch }
- { label: "Dent", value: dent }
- { label: "Missing label", value: label }image_choice
A single selection from a grid of image cards. The value type is string, and each option carries an image field that accepts a relative path or a data URI.
| Field | Description |
|---|---|
options | List of {label, value, image} items. |
columns | Grid column count. Auto-sized when omitted (<=4 → 2, <=9 → 3, else 4). |
aspect | Card aspect ratio. Defaults to 1 (square). Accepts "auto", "square", or a ratio like "16/9". |
fit | Image object-fit mode: cover, contain (default), or fill. |
width / height | Per-card sizing. |
- key: cable_type
type: image_choice
label: "Cable Type"
required: true
options:
- { label: "FFC", value: ffc, image: "./images/cable-ffc.jpg" }
- { label: "Ribbon", value: ribbon, image: "./images/cable-ribbon.jpg" }
- { label: "Harness", value: harness, image: "./images/cable-harness.jpg" }image_checklist
Multiple selections from a grid of image cards. The fields match image_choice, and the value type is string[].
- key: defects
type: image_checklist
label: "Tick all defects you see"
required: false
options:
- { label: "Scratch", value: scratch, image: "./images/scratch.svg" }
- { label: "Dent", value: dent, image: "./images/dent.svg" }
- { label: "Looks OK", value: ok, image: "./images/ok.svg" }Displays
Displays do not gate phase completion, so you assign ui.<key> = value in the phase function to update them live.
text
Read-only text where the value type is string, and updates re-render immediately on the operator screen.
| Field | Description |
|---|---|
size | xs, sm, base (default), lg, xl, 2xl, 3xl, 4xl. |
color | default, zinc, red, orange, yellow, green, lime, sky, blue, violet, purple, pink. |
font | default (sans) or monospace. |
- key: live_voltage
type: text
label: "Live Voltage"
size: 3xl
color: lime
font: monospacedef measure(ui, multimeter):
ui.live_voltage = f"{multimeter.read():.2f} V"image
A static or dynamic image where the value type is string (relative path or data URI). Assign a new path or data URI from Python to swap the image in place.
| Field | Description |
|---|---|
width | CSS width (e.g. "80%", "320px"). Defaults to 100%. |
height | CSS height. Percentages map to viewport height. |
aspect | "auto", "square", or a ratio like "16/9". |
fit | cover (default), contain, fill. |
- key: reference
type: image
default_value: "./images/reference.png"
width: "80%"
aspect: "16/9"
fit: containprogress
A progress bar where the value type is number, which is useful for long-running phases like firmware flashing where you want the operator to see steady forward motion.
| Field | Description |
|---|---|
min | Lower bound. Defaults to 0. |
max | Upper bound. Defaults to 100. |
default_value | Initial value. |
def flash_firmware(ui, programmer):
for percent in programmer.flash():
ui.progress = percentBinding
Inputs can bind their value to a Measurement or a unit field, so bound values appear on the Run automatically and you do not need to assign them from Python.
- key: voltage
type: number_input
bind: measurements.voltage
- key: serial
type: text_input
bind: unit.serial_numberBind paths: measurements.<measurement_key> or unit.<serial_number|part_number|revision_number|batch_number>.
Require continue
Phases with only display components auto-continue once their Python body returns, so you set requires_input when you want to force a Continue button anyway (for example, when the operator has to read a briefing before moving on).
ui:
requires_input: true
components:
- key: briefing
type: text
label: "Read before continuing"
default_value: "Disconnect power before opening the enclosure."How is this guide?