Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

SearchField

SearchField preview

SearchField — a TextInput preset configured for search workflows: leading magnifier glyph, default-on clear-X, and an optional anchored suggestions popover with keyboard navigation and the ARIA combobox-with-listbox accessibility pattern. The popover is shown via OverlayRequest so it floats above sibling content and escapes ancestor clipping (same pattern as ComboBox).

let query = ctx.signal(String::new());
SearchField::new(query.clone())
    .placeholder("Search documents")
    .with_suggestions(|prefix| {
        FRUITS.iter()
            .filter(|f| f.to_lowercase().starts_with(&prefix.to_lowercase()))
            .map(|s| s.to_string())
            .collect()
    })
    .on_select(|value, _ctx| println!("picked: {value}"))
    .on_submit_fn(|ctx| ctx.send_intent(AppIntent::Search))

Design — comparison with searchable ComboBox

A searchable ComboBox and a SearchField are visually similar but semantically different:

  • ComboBox is a value picker — the bound state is the selected item from a known list. The text input is a transient filter, embedded inside the dropdown popup; the closed combo shows the selected value, not the user's query.
  • SearchField is a query input — the bound state is the query string itself. The text input is always visible at the top level; suggestions are completion hints, not the source of truth. The bound Signal<String> keeps whatever the user typed, even if no suggestion matches.

The two share the same dropdown-of-options machinery in spirit; a future refactor could lift a common OverlayList<T> primitive out of both. For now they're separate so each can keep a small API surface tuned to its semantics.

Accessibility

The field is Role::SearchInput with HasPopup::Listbox and AutoComplete::List. When the popup is open it advertises set_expanded(true) and set_controls(listbox_id) (mapped to accesskit::NodeId via widget_id_to_node_id). Each row is Role::ListBoxOption with set_selected(is_highlighted), set_position_in_set(idx + 1), and set_size_of_set(total) so screen readers can announce "Apple, 1 of 5".

Builder methods at a glance

style, placeholder, label, drives_listbox, enabled, on_submit_fn, with_suggestions, max_suggestions, min_chars, on_select, tooltip, rich_tooltip, rich_tooltip_content, composite_tooltip

API reference

📖 Full rustdoc API for this module

pub struct SearchField

A search input with optional inline suggestions popup.

#![allow(unused)]
fn main() {
pub struct SearchField { /* fields */ }
}

Methods

pub fn new(text: Signal<String>) -> Self

Create a search field bound to text, the reactive query string.

pub fn style(mut self, style: impl teksilo_core::styles::SearchFieldStyle) -> Self

Per-call SearchFieldStyle override.

pub fn placeholder(mut self, text: impl Into<LocalizedString>) -> Self

Set the placeholder text shown when the query is empty.

pub fn label(mut self, label: impl Into<LocalizedString>) -> Self

Set an accessible label for the field (announced by screen readers, not visually shown).

pub fn drives_listbox( mut self, listbox: Signal<Option<WidgetId>>, active: Signal<Option<WidgetId>>, ) -> Self

Wire this field to a listbox the caller owns, so arrow keys that move a highlight through that list are announced while focus stays here (the ARIA combobox pattern). listbox is the list's node, active the currently-highlighted row's node; both are forwarded to the inner TextInputField, which is the node that actually holds focus and therefore the only one whose active_descendant assistive technology follows.

This is for a search field driving a list built by its host — a command palette, a filter box above a results view. The built-in suggestion popup (suggestions) wires itself and needs none of this.

pub fn enabled(mut self, on: impl Into<Prop<bool>>) -> Self

Set the initial enabled state. Forwarded to the arena at build time.

pub fn on_submit_fn(mut self, f: impl Fn(&mut EventContext) + 'static) -> Self

Install a callback invoked when the user presses Enter (or activates the search action).

pub fn with_suggestions(mut self, f: impl Fn(&str) -> Vec<String> + 'static) -> Self

Provider that returns suggestions for the current query string. When set, the popup appears below the field as soon as the user types at least Self::min_chars characters and the provider returns a non-empty list.

pub fn max_suggestions(mut self, n: usize) -> Self

Cap the number of suggestions shown in the popup (default 8, minimum 1).

pub fn min_chars(mut self, n: usize) -> Self

Minimum number of characters the user must type before suggestions appear (default 1).

pub fn on_select(mut self, f: impl Fn(&str, &mut EventContext) + 'static) -> Self

Install a callback invoked when the user picks a suggestion (tap, Enter, or Space).

pub fn tooltip(mut self, text: impl Into<LocalizedString>) -> Self

Show a plain one-line tooltip after a hover delay.

Mutually exclusive with rich_tooltip, rich_tooltip_content, and composite_tooltip — calling this clears the other slots (last call wins).

pub fn rich_tooltip(mut self, key: impl Into<String>) -> Self

Show a registry-driven rich tooltip keyed by key.

Mutually exclusive with the other tooltip setters — last call wins.

pub fn rich_tooltip_content(mut self, content: crate::tooltip::TooltipContent) -> Self

Show an inline rich tooltip with the given TooltipContent.

Mutually exclusive with the other tooltip setters — last call wins.

pub fn composite_tooltip(mut self, content: impl Widget + 'static) -> Self

Show a composite tooltip whose body is an arbitrary widget tree.

Mutually exclusive with the other tooltip setters — last call wins.