PettyUI/.firecrawl/kobalte-search.md
2026-03-30 12:08:51 +07:00

22 KiB

Search

Search a searchbox text input with a menu. Handle the case where dataset filtering needs to occur outside the combobox component.

Import

Copyts
import { Search } from "@kobalte/core/search";
// or
import { Root, Label, ... } from "@kobalte/core/search";
Copyts
import { Search } from "@kobalte/core/search";
// or
import { Root, Label, ... } from "@kobalte/core/search";

Features

  • Inherits all the features of combobox, except result filtering which should be managed externally.
  • Debouncing text input to rate limit search suggestions calls.
  • Optional indicator to show when suggestions are loading.

Anatomy

The search consists of:

  • Search: The root container for a search component.
  • Search.Label: The label that gives the user information on the search component.
  • Search.Description: The description that gives the user more information on the component.
  • Search.Control: Contains the search input and indicator.
  • Search.Indicator: Wrapper for icon to indicate loading status.
  • Search.Icon: A small icon often displayed next to the input as a visual affordance for the fact it can be open.
  • Search.Input: The input used to search and reflects the selected suggestion values.
  • Search.Portal: Portals its children into the body when the search is open.
  • Search.Content: Contains the content to be rendered when the search is open.
  • Search.Arrow: An optional arrow element to render alongside the search content.
  • Search.Listbox: Contains a list of items and allows a user to search one or more of them.
  • Search.Section: Used to render the label of an option group. It won't be focusable using arrow keys.
  • Search.Item: An item of the search suggestion.
  • Search.ItemLabel: An accessible label to be announced for the item.
  • Search.ItemDescription: An optional accessible description to be announced for the item.
  • Search.NoResult: Displayed when no suggestion options are given.
Copytsx
<Search>
  <Search.Label />

  <Search.Control>
    <Search.Indicator>
      <Search.Icon />
    </Search.Indicator>
    <Search.Input />
  </Search.Control>

  <Search.Description />

  <Search.Portal>
    <Search.Content>
      <Search.Arrow />
      <Search.Listbox />
      <Search.NoResult>
    </Search.Content>
  </Search.Portal>
</Search>
Copytsx
<Search>
  <Search.Label />

  <Search.Control>
    <Search.Indicator>
      <Search.Icon />
    </Search.Indicator>
    <Search.Input />
  </Search.Control>

  <Search.Description />

  <Search.Portal>
    <Search.Content>
      <Search.Arrow />
      <Search.Listbox />
      <Search.NoResult>
    </Search.Content>
  </Search.Portal>
</Search>

Example

Magnifying Glass

Emoji selected:

index.tsxstyle.css

Copytsx
import { Search } from "@kobalte/core/search";
import { MagnifyingGlassIcon, ReloadIcon } from "some-icon-library";
import { createSignal } from "solid-js";
import "./style.css";

import { queryEmojiData } from "your-search-function";

function App() {
  const [options, setOptions] = createSignal([]);
  const [emoji, setEmoji] = createSignal();
  return (
    <>
      <Search
        triggerMode="focus"
        options={options()}
        onInputChange={query => setOptions(queryEmojiData(query))}
        onChange={result => setEmoji(result)}
        optionValue="name"
        optionLabel="name"
        placeholder="Search an emoji…"
        itemComponent={props => (
          <Search.Item item={props.item} class="search__item">
            <Search.ItemLabel>{props.item.rawValue.emoji}</Search.ItemLabel>
          </Search.Item>
        )}
      >
        <Search.Control class="search__control" aria-label="Emoji">
          <Search.Indicator
            class="search__indicator"
            loadingComponent={
              <Search.Icon class="load__icon">
                <ReloadIcon class="spin__icon" />
              </Search.Icon>
            }
          >
            <Search.Icon class="search__icon">
              <MagnifyingGlassIcon class="center__icon" />
            </Search.Icon>
          </Search.Indicator>
          <Search.Input class="search__input" />
        </Search.Control>
        <Search.Portal>
          <Search.Content class="search__content" onCloseAutoFocus={(e) => e.preventDefault()}>
            <Search.Listbox class="search__listbox" />
            <Search.NoResult class="search__no_result">
              😬 No emoji found
            </Search.NoResult>
          </Search.Content>
        </Search.Portal>
      </Search>
      <div class="result__content">
        Emoji selected: {emoji()?.emoji} {emoji()?.name}
      </div>
    </>
  )
}
Copytsx
import { Search } from "@kobalte/core/search";
import { MagnifyingGlassIcon, ReloadIcon } from "some-icon-library";
import { createSignal } from "solid-js";
import "./style.css";

import { queryEmojiData } from "your-search-function";

function App() {
  const [options, setOptions] = createSignal([]);
  const [emoji, setEmoji] = createSignal();
  return (
    <>
      <Search
        triggerMode="focus"
        options={options()}
        onInputChange={query => setOptions(queryEmojiData(query))}
        onChange={result => setEmoji(result)}
        optionValue="name"
        optionLabel="name"
        placeholder="Search an emoji…"
        itemComponent={props => (
          <Search.Item item={props.item} class="search__item">
            <Search.ItemLabel>{props.item.rawValue.emoji}</Search.ItemLabel>
          </Search.Item>
        )}
      >
        <Search.Control class="search__control" aria-label="Emoji">
          <Search.Indicator
            class="search__indicator"
            loadingComponent={
              <Search.Icon class="load__icon">
                <ReloadIcon class="spin__icon" />
              </Search.Icon>
            }
          >
            <Search.Icon class="search__icon">
              <MagnifyingGlassIcon class="center__icon" />
            </Search.Icon>
          </Search.Indicator>
          <Search.Input class="search__input" />
        </Search.Control>
        <Search.Portal>
          <Search.Content class="search__content" onCloseAutoFocus={(e) => e.preventDefault()}>
            <Search.Listbox class="search__listbox" />
            <Search.NoResult class="search__no_result">
              😬 No emoji found
            </Search.NoResult>
          </Search.Content>
        </Search.Portal>
      </Search>
      <div class="result__content">
        Emoji selected: {emoji()?.emoji} {emoji()?.name}
      </div>
    </>
  )
}

Usage

Debounce

Set debounceOptionsMillisecond, to prevent new search queries immediately on input change. Instead, search queries are requested once input is idle for a set time.

Show a debouncing icon by adding a loadingComponent to Search.Indicator.

Magnifying Glass

Emoji selected:

Copytsx
<Search
  triggerMode="focus"
  options={options()}
  onInputChange={query => setOptions(queryEmojiData(query))}
  onChange={result => setEmoji(result)}
  debounceOptionsMillisecond={300}
  optionValue="name"
  optionLabel="name"
  placeholder="Search an emoji…"
    itemComponent={(props: any) => (
    <Search.Item item={props.item}>
      <Search.ItemLabel>{props.item.rawValue.emoji}</Search.ItemLabel>
    </Search.Item>
  )}
>
  <Search.Control aria-label="Emoji">
    <Search.Indicator
      loadingComponent={
        <Search.Icon>
          <ReloadIcon />
        </Search.Icon>
      }
    >
      <Search.Icon>
        <MagnifyingGlassIcon />
      </Search.Icon>
    </Search.Indicator>
    <Search.Input />
  </Search.Control>
  <Search.Portal>
    <Search.Content onCloseAutoFocus={(e) => e.preventDefault()}>
      <Search.Listbox />
      <Search.NoResult>
        😬 No emoji found
      </Search.NoResult>
    </Search.Content>
  </Search.Portal>
</Search>
Copytsx
<Search
  triggerMode="focus"
  options={options()}
  onInputChange={query => setOptions(queryEmojiData(query))}
  onChange={result => setEmoji(result)}
  debounceOptionsMillisecond={300}
  optionValue="name"
  optionLabel="name"
  placeholder="Search an emoji…"
    itemComponent={(props: any) => (
    <Search.Item item={props.item}>
      <Search.ItemLabel>{props.item.rawValue.emoji}</Search.ItemLabel>
    </Search.Item>
  )}
>
  <Search.Control aria-label="Emoji">
    <Search.Indicator
      loadingComponent={
        <Search.Icon>
          <ReloadIcon />
        </Search.Icon>
      }
    >
      <Search.Icon>
        <MagnifyingGlassIcon />
      </Search.Icon>
    </Search.Indicator>
    <Search.Input />
  </Search.Control>
  <Search.Portal>
    <Search.Content onCloseAutoFocus={(e) => e.preventDefault()}>
      <Search.Listbox />
      <Search.NoResult>
        😬 No emoji found
      </Search.NoResult>
    </Search.Content>
  </Search.Portal>
</Search>

Inline style

To achieve the command menu look, add the open prop to permanently open dropdown. Replace Search.Portal and Search.Content with a div to directly mount your content below the search input.

Magnifying Glass

😬 No emoji found

Emoji selected:

Copytsx
<Search
  open
  options={options()}
  onInputChange={query => setOptions(queryEmojiData(query))}
  onChange={result => setEmoji(result)}
  debounceOptionsMillisecond={300}
  optionValue="name"
  optionLabel="name"
  placeholder="Search an emoji…"
  itemComponent={(props: any) => (
    <Search.Item item={props.item}>
      <Search.ItemLabel>{props.item.rawValue.emoji}</Search.ItemLabel>
    </Search.Item>
  )}
>
  <Search.Control aria-label="Emoji">
    <Search.Indicator>
      <Search.Icon>
        <MagnifyingGlassIcon />
      </Search.Icon>
    </Search.Indicator>
    <Search.Input />
  </Search.Control>
  <div>
      <Search.Listbox />
      <Search.NoResult>
        😬 No emoji found
      </Search.NoResult>
  </div>
</Search>
Copytsx
<Search
  open
  options={options()}
  onInputChange={query => setOptions(queryEmojiData(query))}
  onChange={result => setEmoji(result)}
  debounceOptionsMillisecond={300}
  optionValue="name"
  optionLabel="name"
  placeholder="Search an emoji…"
  itemComponent={(props: any) => (
    <Search.Item item={props.item}>
      <Search.ItemLabel>{props.item.rawValue.emoji}</Search.ItemLabel>
    </Search.Item>
  )}
>
  <Search.Control aria-label="Emoji">
    <Search.Indicator>
      <Search.Icon>
        <MagnifyingGlassIcon />
      </Search.Icon>
    </Search.Indicator>
    <Search.Input />
  </Search.Control>
  <div>
      <Search.Listbox />
      <Search.NoResult>
        😬 No emoji found
      </Search.NoResult>
  </div>
</Search>

API Reference

Search

Search is equivalent to the Root import from @kobalte/core/search.

Prop Description
options `Array<T
optionValue `keyof T
optionTextValue `keyof T
optionLabel `keyof T
optionDisabled `keyof T
optionGroupChildren keyof U
Property name that refers to the children options of an option group.
itemComponent Component<SearchItemComponentProps<T>>
When NOT virtualized, the component to render as an item in the Search.Listbox.
sectionComponent Component<SearchSectionComponentProps<U>>
When NOT virtualized, the component to render as a section in the Search.Listbox.
multiple boolean
Whether the search component allows multi-selection.
placeholder JSX.Element
The content that will be rendered when no value or defaultValue is set.
value `T
defaultValue `T
onChange `(value: T
open boolean
The controlled open state of the search suggestion.
defaultOpen boolean
The default open state when initially rendered. Useful when you do not need to control the open state.
onOpenChange (open: boolean, triggerMode?: SearchTriggerMode) => void
Event handler called when the open state of the search component changes. Returns the new open state and the action that caused the opening of the menu.
onInputChange (value: string) => void
Handler that is called when the search input value changes.
triggerMode SearchTriggerMode
The interaction required to display search suggestion, it can be one of the following:
- input: open search suggestion when the user is typing.
- focus: open search suggestion when the input is focused.
- manual: open search suggestion when pressing arrow down/up while focus is on the input or clicking on the trigger.
removeOnBackspace boolean
When multiple is true, whether the last selected option should be removed when the user press the Backspace key and the input is empty.
allowDuplicateSelectionEvents boolean
Whether onChange should fire even if the new value is the same as the last.
disallowEmptySelection boolean
Whether the search component allows empty selection or not.
allowsEmptyCollection boolean
Whether the search component allows the menu to be open when the collection is empty.
closeOnSelection boolean
Whether the search component closes after selection.
selectionBehavior `'toggle'
virtualized boolean
Whether the search suggestion uses virtual scrolling.
modal boolean
Whether the search component should be the only visible content for screen readers, when set to true:
- interaction with outside elements will be disabled.
- scroll will be locked.
- focus will be locked inside the search component content.
- elements outside the search component content will not be visible for screen readers.
preventScroll boolean
Whether the scroll should be locked even if the search suggestion is not modal.
forceMount boolean
Used to force mounting the search suggestion (portal, positioner and content) when more control is needed. Useful when controlling animation with SolidJS animation libraries.
name string
The name of the search component. Submitted with its owning form as part of a name/value pair.
validationState `'valid'
required boolean
Whether the user must select an item before the owning form can be submitted.
disabled boolean
Whether the search component is disabled.
readOnly boolean
Whether the search component items can be selected but not changed by the user.
autoComplete string
Describes the type of autocomplete functionality the input should provide if any. See MDN
translations SearchIntlTranslations
Localization strings.

Search also accepts the following props to customize the placement of the Search.Content.

Prop Description
placement Placement
The placement of the search component content.
gutter number
The distance between the search component content and the trigger element.
shift number
The skidding of the search component content along the trigger element.
flip `boolean
slide boolean
Whether the search component content should slide when it overflows.
overlap boolean
Whether the search component content can overlap the trigger element when it overflows.
sameWidth boolean
Whether the search component content should have the same width as the trigger element. This will be exposed to CSS as --kb-popper-anchor-width.
fitViewport boolean
Whether the search component content should fit the viewport. If this is set to true, the search component content will have maxWidth and maxHeight set to the viewport size. This will be exposed to CSS as --kb-popper-available-width and --kb-popper-available-height.
hideWhenDetached boolean
Whether to hide the search component content when the trigger element becomes occluded.
detachedPadding number
The minimum padding in order to consider the trigger element occluded.
arrowPadding number
The minimum padding between the arrow and the search component content corner.
overflowPadding number
The minimum padding between the search component content and the viewport edge. This will be exposed to CSS as --kb-popper-overflow-padding.
Data attribute Description
data-valid Present when the search component is valid according to the validation rules.
data-invalid Present when the search component is invalid according to the validation rules.
data-required Present when the user must select an item before the owning form can be submitted.
data-disabled Present when the search component is disabled.
data-readonly Present when the search component is read only.

Search.Label, Search.Control, Search.Input, Search.Trigger, Search.Description and Search.ErrorMesssage shares the same data-attributes.

Search.Control

Render Prop Description
selectedOptions Accessor<T[]>
An array of selected options.
remove (option: T) => void
A function to remove an option from the selection.
clear () => void
A function to clear the selection.

Search.Indicator

Prop Description
loadingComponent JSX.Element
The component that is displayed when suggestion options are being fetched.

Search.Icon

Data attribute Description
data-expanded Present when the search component is open.
data-closed Present when the search component is close.

Search.Content

Data attribute Description
data-expanded Present when the search component is open.
data-closed Present when the search component is close.

Search.Arrow

Prop Description
size number
The size of the arrow.

Search.Listbox

Prop Description
scrollRef `Accessor<HTMLElement
scrollToItem (key: string) => void
When virtualized, the Virtualizer function used to scroll to the item of the given key.
children `(items: Accessor<Collection<CollectionNode<T

Search.Item

Prop Description
item CollectionNode
The collection node to render.
Data attribute Description
data-disabled Present when the item is disabled.
data-selected Present when the item is selected.
data-highlighted Present when the item is highlighted.

Search.ItemLabel and Search.ItemDescription shares the same data-attributes.

Rendered elements

Component Default rendered element
Search div
Search.Label span
Search.Description div
Search.Control div
Search.Indicator div
Search.Icon span
Search.Input input
Search.Portal Portal
Search.Content div
Search.Arrow div
Search.Listbox ul
Search.Section li
Search.Item li
Search.ItemLabel div
Search.ItemDescription div
Search.NoResult div

Accessibility

Keyboard Interactions

Key Description
Enter When focus is virtualy on an item, selects the focused item.
ArrowDown When focus is on the input, opens the search suggestion and virtual focuses the first or selected item.
When focus is virtualy on an item, moves virtual focus to the next item.
ArrowUp When focus is on the input, opens the search suggestion and virtual focuses the last or selected item.
When focus is virtualy on an item, moves virtual focus to the previous item.
Alt + ArrowDown When focus is on the input, opens the search suggestion.
Alt + ArrowUp When focus is on the input, closes the search suggestion.
Home When focus is on the input, moves virtual focus to first item.
End When focus is on the input, moves virtual focus to last item.
Esc When the search suggestion is open, closes the search suggestion.
When the search suggestion is closed, clear the input and selection.

Previous←Rating GroupNextSegmented Control→