Combobox

Combobox is the widget for "type to narrow, then pick" interactions.
It combines a TextInput with a popover list. Your app state owns three things: the current text value, the list of items you want to show right now, and whether the popup is open. That makes the behavior predictable and easy to test, but it also means the widget does not secretly fetch or filter data for you.

Example

use fission::prelude::*;
use std::sync::Arc;

let widget: Widget = Combobox {
id: WidgetId::explicit("assignee_box"),
value: view.state().assignee_query.clone(),
items: view.state().filtered_people.clone(),
is_open: view.state().assignee_open,
width: Some(280.0),
max_popup_height: Some(240.0),
on_change: Some(ctx.bind(
    SetAssigneeQuery(String::new()),
    reduce_with!(on_set_assignee_query),
)),
on_toggle: Some(ctx.bind(
    ToggleAssigneeOpen,
    reduce_with!(on_toggle_assignee_open),
)),
on_select: Some(Arc::new(move |name| ActionEnvelope {
    id: choose_person_id,
    payload: serde_json::to_vec(&ChooseAssignee(name)).unwrap(),
})),
}
.into();
In a real reducer, on_change usually updates the query and refreshes filtered_people, on_toggle opens or closes the popup, and on_select stores the chosen value and closes the popup.

Field table

Field
Type
Meaning
Notes / default behavior
id
WidgetId
Stable identity for the combobox and its popover anchor.
Required.
value
String
Current text shown in the input.
Controlled by app state.
items
Vec<String>
Items to show in the popup right now.
Supply the already filtered list you want the user to see.
is_open
bool
Whether the popup list is visible.
Controlled by app state.
width
Option<f32>
Width of the text field and popup.
Defaults to the input's natural width, with popup width falling back to 320.0.
max_popup_height
Option<f32>
Maximum popup height before scrolling begins.
Defaults to 240.0.
on_change
Option<ActionEnvelope>
Action fired when the user edits the text.
Like TextInput, the runtime replaces the payload with the current String.
on_select
Option<Arc<dyn Fn(String) -> ActionEnvelope + Send + Sync>>
Closure that builds the action for a selected item.
Called with the chosen item string.
on_toggle
Option<ActionEnvelope>
Action used to open or close the popup.
Also used as the close action when the popover dismisses itself.

How the event flow works

There are two different kinds of events here. Typing uses the text-input path: the runtime dispatches on_change with the new string, your reducer stores that query, and the next conversion passes a filtered items list back in. Picking an item uses the on_select closure, which turns the chosen string into an ActionEnvelope immediately.
This split is intentional. Free text and confirmed selection are not the same product event. Keep them separate in your actions.

Specific advice

If the user must choose from a fixed short list and should not type arbitrary text, use Select instead. If you do use a combobox, keep the source of truth in state and derive display lists in selectors or reducers rather than mutating the item list inside the widget.

Production checklist

For Combobox, review the fields that change behavior before treating the widget as finished: id, value, items, is_open, width, max_popup_height. The goal is to make the product rule visible in state and actions, not hidden inside ad-hoc construction code.
Bind on_change, on_select to explicit reducer actions and test that the reducer handles unavailable, duplicate, or invalid input safely.
When child widgets are generated from data, give reordered or filtered rows an explicit WidgetId so retained local state and scroll behavior do not drift between items.
Set id only when identity must be stable across filtering, reordering, diagnostics, or tests; otherwise let Fission derive identity from structure.
Check the semantics tree for the user-facing label or role that makes this widget understandable without relying only on pixels.
Prefer parent layout and design-system sizing first; use explicit size or spacing fields when the product layout requires that constraint on this widget specifically.
Add at least one component or harness test that confirms the visible text, semantic role, action dispatch, and layout constraint that matter for this widget in context.
If a screen starts repeating the same Combobox setup, extract a named component around this widget. That keeps the reference API small while making product code easier to read and safer for generated code to copy.
TextInput, Select, Menu, and FormControl.
Fission
A cross-platform, GPU-accelerated user interface framework for Rust. MIT licensed.
Copyright (c) 2026 Fission
Ready to use today. Widget APIs are expected to remain stable; some runtime and shell APIs may change before 1.0.0.
Fission 0.7.0