SearchSelect
import { SearchSelect, useSearchSelect } from '@tangible/ui';
SearchSelect props
| Prop | Type | Default | Description |
|---|---|---|---|
children |
ReactNode |
||
anchorRef? |
React.RefObject<HTMLElement | null> |
EXTERNAL-TRIGGER MODE: anchor the panel to this element instead of the built-in Trigger. Use with controlled open/onOpenChange and no <SearchSelect.Trigger> — e.g. an IconButton that opens a picker panel under its host field. Provide aria-label (the panel's name — the trigger-labelled path doesn't exist here) and wire the external button's own aria-haspopup/aria-expanded. |
|
aria-describedby? |
string |
||
aria-invalid? |
"false" | "true" | boolean |
||
aria-label? |
string |
||
aria-labelledby? |
string |
||
defaultOpen? |
boolean |
false |
|
defaultValue? |
OptionValue |
Uncontrolled initial value. | |
disabled? |
boolean |
false |
|
filter? |
false | ((textValue: string, query: string) => boolean) |
case-insensitive substring match on textValue |
Built-in filtering: options whose textValue fails this test against the query unmount. Pass false to disable and own the filtering by rendering a different set of Options (async lists). |
id? |
string |
Trigger id — Field.Control injects this. | |
inputValue? |
string |
Controlled search text. Usually uncontrolled — the query is transient and resets when the panel closes. | |
labels? |
SearchSelectLabels |
||
onInputChange? |
(value: string) => void |
Fires as the user types (and on the reset-on-close). | |
onOpenChange? |
(open: boolean) => void |
||
onValueChange? |
(value: OptionValue) => void |
Fires with the committed option value. | |
open? |
boolean |
Controlled open state. | |
placeholder? |
string |
'' |
Trigger text when nothing is selected. |
restoreFocusRef? |
React.RefObject<HTMLElement | null> |
External-trigger mode: where focus returns on commit/Escape (usually the button that opened the panel). Blur onto this element keeps the panel open, so the button's own click handler can toggle without flicker. | |
size? |
"lg" | "md" | "sm" |
'md' |
Control size for the trigger. |
value? |
OptionValue |
Controlled selected value. |
SearchSelect.Trigger
Also exported as SearchSelectTrigger.
| Prop | Type | Default | Description |
|---|---|---|---|
children? |
ReactNode |
Custom trigger content — replaces the default value/placeholder text (the chevron stays). The fields dynamic-value picker renders its bolt + type + key pill here. NOTE: with an aria-label on the Root the accessible name is frozen to that label — custom content is then invisible to AT (family-wide follow-up in the roadmap). |
|
className? |
string |
Also accepts the standard attributes of ButtonHTMLAttributes (data-*, aria-*, event handlers), passed to the element it renders.
SearchSelect.Content
Also exported as SearchSelectContent.
| Prop | Type | Default | Description |
|---|---|---|---|
children? |
ReactNode |
||
className? |
string |
SearchSelect.Option
Also exported as SearchSelectOption.
| Prop | Type | Default | Description |
|---|---|---|---|
value |
OptionValue |
||
children? |
ReactNode |
||
className? |
string |
||
disabled? |
boolean |
false |
|
textValue? |
string |
Required when children is not a plain string. |
SearchSelect.Group
Also exported as SearchSelectGroup.
| Prop | Type | Default | Description |
|---|---|---|---|
children? |
ReactNode |
||
className? |
string |
SearchSelect.Label
Also exported as SearchSelectLabel.
| Prop | Type | Default | Description |
|---|---|---|---|
children? |
ReactNode |
||
className? |
string |
Hooks
useSearchSelect
useSearchSelect(): SearchSelectContextValue
Public escape hatch, mirroring useSelect/useCombobox.
Returns:
| Member | Type | Description |
|---|---|---|
disabled |
boolean |
|
placeholder |
string |
|
size |
"lg" | "md" | "sm" |
|
labels |
Required<SearchSelectLabels> |
|
triggerId |
string |
|
listboxId |
string |
|
panelId |
string |
|
ariaLabel? |
string |
|
ariaLabelledBy? |
string |
|
ariaDescribedBy? |
string |
|
ariaInvalid? |
"false" | "true" | boolean |
|
setOpen |
(open: boolean) => void |
|
selectValue |
(value: OptionValue, textValue: string) => void |
|
setInputValue |
(value: string) => void |
|
registerOption |
(option: RegisteredOption) => void |
|
unregisterOption |
(optionValue: OptionValue) => void |
|
labelFor |
(value: OptionValue) => string |
|
returnFocus |
() => void |
Focus the trigger (or restoreFocusRef in external-trigger mode). |
handlePanelBlur |
(e: React.FocusEvent) => void |
|
handleInputKeyDown |
(e: React.KeyboardEvent) => void |
|
refs |
{ reference: RefObject<ReferenceType | null>; floating: RefObject<HTMLElement | null>; setReference: (node: ReferenceType | null) => void; setPositionReference: (node: ReferenceType | null) => void; setFloating: (node: HTMLElement | null) => void; } |
|
triggerElRef |
MutableRefObject<HTMLButtonElement | null> |
|
anchorRef? |
React.RefObject<HTMLElement | null> |
External-trigger mode anchor (see SearchSelectProps.anchorRef). |
inputRef |
MutableRefObject<HTMLInputElement | null> |
|
listRef |
MutableRefObject<(HTMLElement | null)[]> |
|
optionIndexMap |
Map<string, number> |
|
context |
FloatingContext |
|
getReferenceProps |
(userProps?: React.HTMLProps<Element>) => Record<string, unknown> |
|
getFloatingProps |
(userProps?: React.HTMLProps<HTMLElement>) => Record<string, unknown> |
|
getItemProps |
(userProps?: React.HTMLProps<HTMLElement>) => Record<string, unknown> |
|
open |
boolean |
|
value |
OptionValue | undefined |
|
inputValue |
string |
|
query |
string |
|
filter |
false | ((textValue: string, query: string) => boolean) |
|
activeIndex |
number |
|
activeOptionId |
string | undefined |
|
orderedOptions |
RegisteredOption[] |
|
floatingStyles |
CSSProperties |
RegisteredOption (the option of registerOption):
| Member | Type | Description |
|---|---|---|
value |
OptionValue |
|
ref |
RefObject<HTMLElement | null> |
|
disabled |
boolean |
|
textValue |
string |
Examples
-
External trigger (anchorRef): EXTERNAL-TRIGGER MODE: no
SearchSelect.Trigger— an IconButton opens a controlled panel anchored to the host field viaanchorRef, with focus returning to the button viarestoreFocusRef. The fields dynamic-value insert affordance is exactly this shape. -
With Field Error: SearchSelect inside Field with Field.Error —
aria-invalidlands on the trigger, the element wearingtui-input-group, so the danger border lights.No
aria-requiredcounterpart: the trigger isaria-haspopup="dialog"on a plain button, androle="button"does not support that attribute. Field.Label carries the requirement instead.
Other stories: Default, With default value, In a Field, Custom trigger content, Sizes, Disabled.
Component API tokens
Read via fallback, never declared. Set one on an ancestor to restyle every instance under it.
--tui-search-select-trigger-bg--tui-search-select-trigger-fg--tui-search-select-trigger-border--tui-search-select-trigger-border-hover--tui-search-select-trigger-border-focus--tui-search-select-trigger-radius--tui-search-select-panel-bg--tui-search-select-panel-fg--tui-search-select-panel-border--tui-search-select-panel-shadow--tui-search-select-panel-radius--tui-search-select-panel-width--tui-search-select-option-bg-hover--tui-search-select-option-bg-selected--tui-search-select-option-fg-hover--tui-search-select-option-fg-selected--tui-search-select-option-bg-selected-hover--tui-search-select-option-check