4.3k

Combobox

combobox is a trigger-only primitive like select, but the trigger is a text entry with a menu affordance: on-input names a Msg variant that receives every edit as a canvas.TextInputEvent, and the model filters the options as the user types. The options themselves are composed the same way as the select's — an anchored dropdown-menu of menu-items beside the trigger in a stack, rendered under an if, with on-dismiss clearing the model's open flag when Escape or a click outside closes the surface.

combobox
A combobox rendered by the engine (light theme)
a combobox trigger with its search placeholder

Markup

The model owns the query and the open flag; the for source is the model-filtered match list, so the menu narrows as the user types.

<stack width="240">
  <combobox placeholder="Search frameworks" text="{framework_query}" on-input="framework_edited" on-press="open_framework_menu" />
  <if test="{framework_menu_open}">
    <dropdown-menu anchor="below" anchor-alignment="stretch" on-dismiss="close_framework_menu">
      <for each="matchingFrameworks" key="id" as="f">
        <menu-item on-press="pick_framework:{f.id}">{f.name}</menu-item>
      </for>
    </dropdown-menu>
  </if>
</stack>

Zig builder

on_input takes a comptime message constructor: Ui.inputMsg(.tag) builds Msg{ .tag = edit } for each canvas.TextInputEvent.

ui.stack(.{ .width = 240 }, .{
    ui.el(.combobox, .{
        .placeholder = "Search frameworks",
        .text = model.framework_query,
        .on_input = Ui.inputMsg(.framework_edited),
        .on_press = .open_framework_menu,
    }, .{}),
    if (model.framework_menu_open) ui.el(.dropdown_menu, .{
        .anchor = .below,
        .anchor_alignment = .stretch,
        .on_dismiss = .close_framework_menu,
    }, .{
        ui.el(.menu_item, .{ .text = "Native SDK", .on_press = .{ .pick_framework = 0 } }, .{}),
        ui.el(.menu_item, .{ .text = "Canvas", .on_press = .{ .pick_framework = 1 } }, .{}),
    }) else ui.spacer(0),
})

Attributes

AttributeDescription
textText value for text-bearing elements; a literal or one {binding}.
placeholderHint text shown while a text entry is empty.
disabledDisables the control; true/false or a {binding}.
on-pressDispatch a Msg on press: tag or tag:{payload}. Legal on any element — a bound press handler makes it pressable, and presses on plain text/icons inside it fall through to it (dragging still selects text).
on-inputNames a Msg variant with canvas.TextInputEvent payload; delivers each text edit.
on-dismissDismissible surfaces only (dialog, drawer, sheet, dropdown-menu): Msg dispatched when Escape or a click outside dismisses the surface, so the MODEL owns the close (clear the open flag in update). The engine hides the surface immediately as an optimistic echo; the source tree wins on the next rebuild.