AutoCompleteInput
Search a suggestion list with native text input, keyboard selection and separate query and selected-value state.
AutoCompleteInputFind a region
Type a label, value or keyword; choose a result with the mouse or arrow keys and Enter. Toggle loading and disabled states to inspect their behavior.
<RegorApp id="auto-complete-input-demo" src="./playground.ts"/> import {
type AutoCompleteOption,
type AutoCompleteValue,
defineAutoCompleteInputComponents,
defineButtonComponents,
defineFlexComponents,
defineFormComponents,
defineFormInputField,
defineIconComponents,
} from '@purestack/ts-components'
import {
lucide_check,
lucide_chevron_down,
lucide_loader_circle,
} from '@purestack/ts-svg-icons'
import { createApp, defineComponent, html, type Ref, ref } from 'regor'
export interface AutoCompleteInputExample {
searchQuery: Ref<string>
chosenRegion: Ref<AutoCompleteValue | null>
regionOptions: AutoCompleteOption[]
pending: Ref<boolean>
locked: Ref<boolean>
reset: () => void
}
const autoCompleteInputExampleTemplate = html`<Flex direction="column">
<AutoCompleteInput
id="auto-region"
label="Deployment region"
placeholder="Try Europe or Frankfurt"
:model="searchQuery"
:selectedValue="chosenRegion"
:options="regionOptions"
:loading="pending"
:disabled="locked"
emptyText="No matching region"
/>
<Flex wrap="true">
<FormCheck id="auto-loading" label="Loading state" :checked="pending" />
<FormCheck id="auto-disabled" label="Disabled state" :checked="locked" />
<Btn variant="link" @click="reset">Clear selection</Btn>
</Flex>
<FormStatus>
Query: {{ searchQuery || 'Empty' }} ยท Selected value: {{ chosenRegion ?? 'None'
}}
</FormStatus>
</Flex>`
function createAutoCompleteInputExample(): AutoCompleteInputExample {
const searchQuery = ref('')
const chosenRegion = ref<AutoCompleteValue | null>(null)
return {
searchQuery,
chosenRegion,
pending: ref(false),
locked: ref(false),
regionOptions: [
{ label: 'Europe Central', value: 'eu-central', keywords: ['Frankfurt'] },
{ label: 'US East', value: 'us-east', keywords: ['Virginia'] },
{ label: 'Asia Pacific', value: 'apac', keywords: ['Singapore'] },
{
label: 'Private region ยท unavailable',
value: 'private',
disabled: true,
},
],
reset: () => {
searchQuery('')
chosenRegion(null)
},
}
}
const component = defineComponent<AutoCompleteInputExample>(
autoCompleteInputExampleTemplate,
{
context: createAutoCompleteInputExample,
},
)
const icons: Record<string, string> = {
'lucide:loader-circle': lucide_loader_circle,
'lucide:check': lucide_check,
'lucide:chevron-down': lucide_chevron_down,
}
createApp(
{
components: {
AutoCompleteInputExample: component,
...defineAutoCompleteInputComponents(),
...defineFormInputField(),
...defineFlexComponents(),
...defineFormComponents(),
...defineButtonComponents(),
...defineIconComponents((name) => icons[name] ?? ''),
},
},
{
selector: 'app#auto-complete-input-demo',
template: html`<AutoCompleteInputExample />`,
},
) A custom suggestion row
Rows can show richer context while the parent owns listbox semantics and selection. This example waits for one character and limits results to three.
<RegorApp id="auto-custom-row-demo" src="./custom-row.ts"/> import {
type AutoCompleteOption,
defineAutoCompleteInputComponents,
defineBadgeComponents,
defineButtonComponents,
defineFlexComponents,
defineFormComponents,
defineFormInputField,
defineIconComponents,
type ResolvedAutoCompleteOption,
} from '@purestack/ts-components'
import { lucide_check, lucide_chevron_down } from '@purestack/ts-svg-icons'
import {
createApp,
defineComponent,
html,
type Ref,
type RefOrValue,
ref,
} from 'regor'
export interface ServiceSuggestion {
option: RefOrValue<ResolvedAutoCompleteOption | null>
selected: RefOrValue<boolean>
}
const serviceSuggestionTemplate = html`<Flex align="center" justify="between">
<span>
<strong>{{ option?.label }}</strong>
<small class="d-block">Service ID: {{ option?.value }}</small>
</span>
<Badge r-if="selected" tone="success">Selected</Badge>
</Flex>`
const serviceSuggestion = defineComponent<ServiceSuggestion>(
serviceSuggestionTemplate,
{ props: ['option', 'selected'] },
)
export interface CustomSuggestions {
serviceQuery: Ref<string>
serviceOptions: AutoCompleteOption[]
}
const customSuggestionsTemplate = html`<AutoCompleteInput
id="auto-service"
label="Service"
:model="serviceQuery"
:options="serviceOptions"
rowComponent="ServiceSuggestion"
:minLength="1"
:maxResults="3"
placeholder="Type API or mail"
/>`
function createCustomSuggestions(): CustomSuggestions {
return {
serviceQuery: ref(''),
serviceOptions: [
{ label: 'Identity API', value: 'identity', keywords: ['auth'] },
{ label: 'Mail gateway', value: 'mail', keywords: ['email'] },
{ label: 'Billing API', value: 'billing', keywords: ['invoice'] },
],
}
}
const component = defineComponent<CustomSuggestions>(
customSuggestionsTemplate,
{
context: createCustomSuggestions,
},
)
const icons: Record<string, string> = {
'lucide:check': lucide_check,
'lucide:chevron-down': lucide_chevron_down,
}
createApp(
{
components: {
CustomSuggestions: component,
ServiceSuggestion: serviceSuggestion,
...defineAutoCompleteInputComponents(),
...defineFormInputField(),
...defineFlexComponents(),
...defineFormComponents(),
...defineButtonComponents(),
...defineBadgeComponents(),
...defineIconComponents((name) => icons[name] ?? ''),
},
},
{
selector: 'app#auto-custom-row-demo',
template: html`<CustomSuggestions />`,
},
) Behavior and accessibility
Arrow keys move through enabled suggestions; Enter selects, Escape closes. Search matches labels, values and keywords case-insensitively. Editing the query can clear selectedValue. Query text alone is not proof that an option was selected. Keep custom rows free of nested interactive controls.
API reference
AutoCompleteInput contract
Props below are the public template API. RefOrValue accepts a literal or a reactive ref; bind refs with a colon-prefixed attribute. Native attributes and events can be passed through the component root.
id
RefOrValue<string> - Default
generated
Unique control ID. Supply an explicit value when help text or another element needs to reference this control.
label
RefOrValue<string> - Default
not set
Visible label. Use language that describes the control or value in its surrounding context.
tone
RefOrValue<SemanticTone> - Default
inherited
Semantic intent: neutral, accent, secondary, info, success, warning, danger, feature, custom or ghost. The active skin supplies the colors.
variant
RefOrValue<ComponentVariant> - Default
inherited FormInputField surfaceAlt
Visual treatment. Accepts solid, surface, surfaceAlt, spotlight, glass, flat, flatAlt, flatSolid, outlineFill, outline, subtle, subtleBtn, link, sheen, underline, rail, bracket or none.
model
Ref<string> - Default
ref('')
Two-way value ref. Pass the ref itself with :model="fieldValue" so edits update application state.
selectedValue
Ref<AutoCompleteValue | null> - Default
ref(null)
Selected option value, independent of the editable query model.
type
RefOrValue<FormInputFieldType> - Default
search
Native input type forwarded to FormInputField.
name
RefOrValue<string> - Default
not set
Native form field name used during FormData serialization.
required
RefOrValue<boolean> - Default
false
Native required constraint. Validate the owning form before accepting its data.
autocomplete
RefOrValue<string> - Default
off
Native browser autofill hint, such as name, email or current-password.
placeholder
RefOrValue<string> - Default
not set
A short input hint shown while empty. Keep a separate visible label.
disabled
RefOrValue<boolean> - Default
false
Disables interaction. Use a bound boolean, for example :disabled="isLocked".
icon
RefOrValue<string> - Default
not set
Registered SVG icon name. In browser apps, include the icon in the resolver passed to defineIconComponents.
iconEnd
RefOrValue<string> - Default
lucide:chevron-down; loader-circle while loading
Trailing input icon. Include both default icons in the browser resolver when the loading state is used. An explicit iconEnd overrides both.
options
RefOrValue<AutoCompleteOption[]> - Default
[]
Suggestion or select data. Each option has a label, an optional value and an optional disabled flag. Omitted values use the label.
rowComponent
RefOrValue<string> - Default
AutoCompleteOptionRow
Registered suggestion row component. Receives option, item, index, query, active, selected and disabled. The parent supplies the clickable option wrapper.
minLength
RefOrValue<number | string> - Default
0
Minimum trimmed query length before suggestions may open.
maxResults
RefOrValue<number | string> - Default
10
Maximum number of matching suggestions rendered.
openOnFocus
RefOrValue<boolean> - Default
true
Opens suggestions on focus when the minimum query length is met.
loading
RefOrValue<boolean> - Default
false
Shows a loading state. Your application supplies options and manages any asynchronous request.
emptyText
RefOrValue<string> - Default
No suggestions
Message displayed when the query has no matching suggestions.
loadingText
RefOrValue<string> - Default
Loading suggestions
Status message while loading is true.
onSelect
(option: ResolvedAutoCompleteOption) => void - Default
not set
Callback receiving a ResolvedAutoCompleteOption after selection.
onSearch
(query: string) => void - Default
not set
Callback receiving the query string after an edit. Use it to load or filter application data.
Composition
No slots. Register defineAutoCompleteInputComponents, defineFormInputField and defineIconComponents. Custom rows are registered under the name passed to rowComponent.
Option and event contracts
interface AutoCompleteOption {
label: RefOrValue<string>
value?: RefOrValue<string | number>
disabled?: RefOrValue<boolean>
keywords?: RefOrValue<string | string[]>
} The component also emits optionselect and querychange. Use callbacks or emitted events for application integration; avoid processing the same change through both paths.