Pickers

Select

Pick one value from a dropdown list.

Rust
1use herogpui::components::select::Select;

Usage

Use the arrow keys and Enter or Space to select a language. Selection closes the list and keeps focus on the trigger. Values and options use 14px text with 20px lines. Section headers use 12px text with 16px lines and keep their own spacing. The popup flips near window edges and scrolls to keep options reachable in short windows.

Rust
1use herogpui::prelude::Select;
2
3Select::new("select-main", languages())
4    .label("Language")
5    .placeholder("Choose one")
6    .value(selected)
7    .is_open(is_open)
8    .on_open_change(bool_cb(cx.listener(|this, open: &bool, _, cx| {
9        this.select_open = *open;
10        cx.notify();
11    })))
12    .on_change(opt_usize_cb(cx.listener(
13        |this, i: &Option<usize>, _, cx| {
14            this.select_lang = *i;
15            this.select_open = false;
16            cx.notify();
17        },
18    )))

Live HeroGPUI compiled to WebAssembly. Select any example without loading another WASM instance.

Anatomy

Rust types

Select

Select is assembled from these builders. The API reference lists each one.

Customization

Appearance builders and theme tokens Select uses.

Styling

Select styling
StyleDescription
Select text_size + line_height + section header stylesText keeps its line height under surrounding styles. Section headers have 8px horizontal, 6px top and 4px bottom padding; selecting an option does not add font weight.
conditional flex_col + gap(px(4.)) + default max_w(px(320.))The inner field wrapper stacks at four pixels only when label or description content exists; the root adds a 320px cap unless full width is enabled.
description rendered only when !is_invalidDescription text is suppressed while the field is invalid.
Label natural widthThe shared label has natural content but does not explicitly opt out of flex-column stretching.
h(px(36.)) + px(px(12.)) + field chromePrimary trigger dimensions, chrome and typography.
static trigger stylePinned property transitions are immediate in GPUI.
hover backgroundHover field background.
ring_if_focused + field focus backgroundRing and background match; the focus background does not interpolate.
invalid field border/ring + focus backgroundInvalid field treatment and focus background.
disabled_opacity + listener suppressionDisabled opacity and interaction treatment.
FieldVariant::SecondaryLower-emphasis secondary trigger.
flex_1 + text_size(px(14.)) + truncateAlignment and size match, but GPUI truncates instead of wrapping long values.
muted foregroundPlaceholder colour.
SelectionValue text/items onlySelected-value rendering does not include option checkmarks.
chevron_down/chevron_upGPUI uses a flow-positioned chevron and swaps glyphs without rotation animation.
scrollable_field_popover + max_h_full (plain) / Infer (virtual) + floating_radius + overlay_shadowAnchored to the measured trigger width with an 8px gap, flipping to the side with more room when the preferred side cannot fit and keeping a 12px cross-axis viewport inset with the scroller capped to the available height; the plain list scrolls the panel and the virtual list sizes itself to the same bound. Overlay surface, radius and shadow.
Motion::LIST_IN + entering_zoomFade and zoom match; transform origin and placement slide are absent.
Motion::LIST_OUT + exitingExit motion matches.
panel p(px(6.)) + option px(px(10.))Six-pixel list inset and ten-pixel option-row horizontal padding.
static indicatorGPUI has no indicator transition in either selection mode.
root.w_full() + field.w_full()Both the root and trigger expand to the available container width.

API reference

Builders

Select builders
BuilderTypeDefaultDescription
placeholder(text)text'Select an item'Temporary text shown while no option is selected.
selection_mode(SelectionMode)SelectionModeSelectionMode::SingleChooses single or multiple selection.
is_open(bool)boolControlled popover open state.
default_open(bool)boolInitial uncontrolled popover state.
on_open_change(callback)Fn(isOpen: bool) -> ()Reports popover state changes.
disabled_keys(keys)iterable of keysKeys which cannot be selected or focused.
is_disabled(bool)boolDisables the field and its interactions.
value(Option<usize>) / selected_indices(indices)Option<usize> / Key | Key[] | nullControlled selection; GPUI separates scalar and multiple values into typed builders.
default_value(Option<usize>) / default_selected_indices(indices)Option<usize> / Key | Key[] | nullInitial uncontrolled scalar or multiple selection, seeded once.
on_change(callback) / on_selection_change_all(callback)Fn(value: Key | Key[] | null) -> ()Selection callback; scalar and multiple signatures use separate builders.
is_required(bool)boolDraws the required marker and makes an empty live FormField block native submission and focus the trigger.
is_invalid(bool)boolForces the field into its invalid state.
name(name)stringExports a live single- or multiple-selection FormField with disabled omission and reset behavior.
full_width(bool)boolfalseExpands both the root and trigger to the available width.
variant(FieldVariant)FieldVariantFieldVariant::PrimarySelects the shadowed or lower-emphasis field chrome.
new(id, options)id, optionsCompound parts; GPUI takes a typed option collection and draws the field structure.
value_content(render)AnyElement | render closureCustom value content receives the live selected-value projection.
indicator(render)AnyElementThe similarly named GPUI builder replaces option checkmarks, not the trigger chevron.
placement(Placement)PlacementPlacement::BottomEight cardinal/start/end placements are available; RAC's full 22-value placement union is not. The panel anchors to the measured trigger with an 8px gap and flips when the preferred side cannot fit and the opposite side has more room.

Parts

Select parts
PartDescription
SelectSelection, form and overlay state owner.
SelectFocus and press target; its internal content is not separately composable.
SelectPlaceholder or selected-value content with a live render projection.
SelectBuilt-in trigger chevron; the public indicator closure belongs to list options instead.
SelectList surface anchored to the trigger; it can flip within the window and supports a reduced placement vocabulary.

States

Select states
BuilderStateDescription
trigger hover styleHovered triggerField background changes on pointer hover.
ring_if_focused + focus-visible backgroundFocus visibleKeyboard focus rings the trigger and applies the field-focus background. Enter and Space finish a single selection without reopening a popup closed by its owner.
is_disabled + live FormField is_successfulDisabledField is dimmed, inert, untabbable and omitted from FormData while disabled.
is_invalid + description suppressionInvalidInvalid field chrome applies the focus background and suppresses the description row.
SelectionValue::is_placeholderPlaceholderEmpty value uses muted placeholder colour.
is_open chevron selectionOpen indicatorThe glyph swaps direction immediately instead of rotating over 150ms.
overlay_phase Entering + entering_zoomEntering150ms Smooth fade and 95% zoom match; placement-specific four-pixel translation is absent.
overlay_phase Exiting + exitingExiting100ms Smooth fade and zoom to 95%.
selected option style + indicatorSelected optionSelection is visible, but GPUI adds accent text and weight beyond v3's indicator-only state.
focused option borderFocused optionKeyboard focus is visible, but uses a two-pixel border rather than v3's status ring.
disabled_keysDisabled optionDisabled rows are dimmed and skipped by navigation and selection.
SelectionMode::MultipleMultiple selectionThe popover stays open while multiple options are toggled.