For AI agents: the complete documentation index is available at /ooui-react/en/llms.txt, the full documentation bundle is available at /ooui-react/en/llms-full.txt, and this page is available as Markdown at /ooui-react/en/components/search-widget/index.md.
  • English
  • SearchWidget

    Source | Original component

    A search widget: a query box with an always-visible results list.

    Basic usage

    The component doesn't set a height on its own: query and results are absolutely positioned and the root element carries no height. It's recommended to give the root element a height (a fixed height, height: 100%, or flex: 1 in a flex column all work), otherwise the results list overflows the widget box. The demo also adds position: relative to the root so those regions anchor to the widget itself (by default they anchor to the nearest positioned ancestor).

    Apple
    Banana
    Orange
    Grape
    Melon
    Chosen: (nothing chosen)
    import { useState } from "react";
    import { SearchWidget } from "ooui-react";
    
    const data = ["Apple", "Banana", "Orange", "Grape", "Melon"];
    
    function App() {
      const [query, setQuery] = useState("");
      const [picked, setPicked] = useState("(nothing chosen)");
    
      // The caller filters and fills results from the query
      const results = data
        .filter((name) => name.toLowerCase().includes(query.toLowerCase()))
        .map((name) => ({ value: name, children: name }));
    
      return (
        <div style={{ display: "flex", flexDirection: "column", gap: 8, maxWidth: 320 }}>
          <SearchWidget
            value={query}
            onQueryChange={setQuery}
            onChoose={(v) => setPicked(String(v))}
            results={results}
            placeholder="Search fruit…"
            style={{ height: 280, position: "relative" }}
          />
          <div>Chosen: {picked}</div>
        </div>
      );
    }
    
    export default App;

    Query and choosing

    • value / defaultValue / onQueryChange are the query box's controlled/uncontrolled channels (there is no onChange; query changes go through onQueryChange).
    • Each results item is standard option data (with value and children).
    • onChoose fires when a result is chosen (Enter on the highlighted result, or clicking one). The highlight clears whenever the results set or query changes.
    • The component implements no searching; real use is mostly async: fire the request in onQueryChange, optionally empty results while loading and fill them in when ready — the highlight clears automatically on every results/query change, no manual reset needed.
    • inputProps is a two-layer channel: SearchInput-level props are passed directly; props meant for the native <input> (aria-*, autoComplete, etc.) go through inputProps.inputProps (TextInput's input-element channel). inputProps.inputRef is merged — that input doubles as the focus owner for the results list's aria-activedescendant.

    Keyboard and focus

    Focus always stays in the query box: ↑↓ move the highlight among results (wrapping at the ends), Enter chooses the current highlight. The clear indicator on the query box comes from SearchInput — it appears when there's a value and clears on click.

    API

    PropDescriptionTypeDefault
    resultsResult option set, filled by the caller from the querySelectOptionProps[][]
    valueQuery text (controlled)string—
    defaultValueInitial query for uncontrolled usestring''
    onQueryChangeQuery-change callback (refill results from it)ChangeHandler<string>—
    onChooseResult-chosen callbackChangeHandler<string | number>—
    placeholderQuery box placeholderstring—
    inputPropsOverrides for the query box (SearchInput); a two-layer channel, see Query and choosing; value/defaultValue/onChange are taken overobject—
    disabledWhether disabledbooleanfalse
    ...restNative div props passed straight to the rootHTMLAttributes<HTMLDivElement>—

    See also