Picker (built-in)
Authoring
use day::prelude::*;
let size = Signal::new(1usize);
picker(["Small", "Medium", "Large"], size).segmented().id("size") // horizontal one-of-N
picker(colors, color).menu() // dropdown / pop-up
picker(plans, plan).inline() // vertical radio group
picker(options, selected) takes fixed options (impl IntoIterator<Item: Into<String>>) and a
Signal<usize> bound two-way (the widget writes the selected index back; setting the signal moves the
widget). Default style is .menu(); .segmented() / .inline() / .style(PickerStyle) switch it.
Picker implements Piece, so .id()/.a11y()/.frame() chain via Decorate.
Options that come from data
The labels are fixed by default. When they are not (a list of open documents, a tab that names
its own contents), .options_reactive(f) recomputes them:
picker(tab_labels(), tab) // seeds the control
.segmented()
.options_reactive(tab_labels) // …and patches it whenever they change
f runs like any other reactive read, so it re-fires when the signals it touches change, and the
new labels patch the native items in place: the pop-up refills, the segmented control relabels and
grows or shrinks its buttons, the radio group does the same. The selected index is preserved where
it still exists and clamped to the last option otherwise, so a shrinking list cannot leave a native
control with nothing chosen. The app still owns the value: write a valid index to the binding when
the count changes under it.
Use it only when the options change. Rebuilding a native menu costs more than moving a mark, and a picker whose choices are constant should stay constant.
Per-backend native realization
| style | AppKit | UIKit | GTK | Qt | Android | XAML | ArkUI |
|---|---|---|---|---|---|---|---|
| Menu | NSPopUpButton | UIButton+UIMenu pull-down | GtkDropDown | QComboBox | Spinner | ComboBox | TextPicker wheel |
| Segmented | NSSegmentedControl | UISegmentedControl | .linked grouped GtkToggleButtons | checkable QPushButtons in a QButtonGroup | button-row LinearLayout (dim unselected) | horizontal RadioButton StackPanel | TextPicker wheel |
| Inline | vertical NSStackView of radio NSButtons | checkmark-row UIStackView | grouped GtkCheckButtons (radio) | QRadioButtons in a QButtonGroup | RadioGroup | vertical RadioButton StackPanel | TextPicker wheel |
HarmonyOS has no segmented control, so ArkUI renders every style as the native ARKUI_NODE_TEXT_PICKER
wheel, the platform’s option-selection idiom. The Qt and XAML renderers each carry a C++ shim in the
matching -sys crate (toolkits/day-qt-sys/src/shim-picker.cpp,
toolkits/day-xaml-sys/src/shim-picker.cpp); the XAML shim boxes its XAML element into a Day handle
through the day_xaml_box/day_xaml_unbox functions. Android’s Java factory
(toolkits/day-android/java/dev/daybrite/day/piece/picker/DayPicker.java) rides the framework shim.
All backends report selection through Event::SelectionChanged(i64); programmatic selection is
echo-guarded per backend so it never loops.
Verification
The showcase Controls page (controls.rs pickers_section) shows all three styles bound to one
shared selection signal, each with a live value label. Rendering and correct initial selection are
screenshot-verified on all 5 local targets (AppKit, GTK, Qt, iOS-sim, Android-emu); a mock-backend
test (crates/day-pieces/tests/mock_e2e.rs picker_and_text_area_are_built_in) asserts the two-way
binding round-trips. The walkthrough drives select through each styling and asserts the readouts
follow.
Follow-ups
- Reactive
options(currently fixed at build; onlyselectedpatches), mirroring the combobox’sItems. - Disabled/enabled state; per-option a11y labels.