MultiAutoCompleteInput

Select several suggestions, create new tokens and keep a structured list separate from the current query.

MultiAutoCompleteInput

View source · API reference

Tag a release

Choose suggestions, type a new tag and press Enter, or paste comma-separated values. The Documentation tag is locked; remove other tags individually or clear them together.

<RegorApp id="multi-auto-complete-input-demo" src="./playground.ts"/>
import {
  type AutoCompleteOption,
  defineButtonComponents,
  defineFlexComponents,
  defineFormComponents,
  defineIconComponents,
  defineMultiAutoCompleteInputComponents,
  type MultiAutoCompleteItem,
} from '@purestack/ts-components'
import {
  lucide_chevron_down,
  lucide_loader_circle,
  lucide_x,
} from '@purestack/ts-svg-icons'
import {
  createApp,
  defineComponent,
  html,
  type Ref,
  ref,
  type SRef,
  sref,
} from 'regor'

export interface MultiAutoCompleteInputExample {
  selectedTags: SRef<MultiAutoCompleteItem[]>
  tagQuery: Ref<string>
  tagOptions: AutoCompleteOption[]
  customAllowed: Ref<boolean>
  duplicatesAllowed: Ref<boolean>
  pending: Ref<boolean>
  locked: Ref<boolean>
  clear: () => void
}

const multiAutoCompleteInputExampleTemplate = html`<Flex direction="column">
  <MultiAutoCompleteInput
    id="multi-tags"
    label="Release tags"
    placeholder="Choose or type a tag"
    name="tags"
    :items="selectedTags"
    :model="tagQuery"
    :options="tagOptions"
    :allowCustomValues="customAllowed"
    :allowDuplicates="duplicatesAllowed"
    :loading="pending"
    :disabled="locked"
    separators=",;"
  />
  <Flex wrap="true">
    <FormCheck id="multi-custom" label="Allow new tags" :checked="customAllowed" />
    <FormCheck
      id="multi-duplicates"
      label="Allow duplicates"
      :checked="duplicatesAllowed"
    />
    <FormCheck id="multi-loading" label="Loading state" :checked="pending" />
    <FormCheck id="multi-disabled" label="Disabled" :checked="locked" />
  </Flex>
  <Btn variant="link" @click="clear">Clear editable tags</Btn>
  <FormStatus>
    {{ selectedTags.length }} tags selected. Query: {{ tagQuery || 'Empty' }}
  </FormStatus>
  <ul>
    <li r-for="tag in selectedTags">{{ tag.label }} · {{ tag.value }}</li>
  </ul>
</Flex>`

function createMultiAutoCompleteInputExample(): MultiAutoCompleteInputExample {
  const requiredTag: MultiAutoCompleteItem = {
    label: 'Documentation',
    value: 'docs',
    disabled: true,
  }
  const selectedTags = sref<MultiAutoCompleteItem[]>([
    requiredTag,
    { label: 'Needs review', value: 'review', tone: 'warning' },
  ])
  return {
    selectedTags,
    tagQuery: ref(''),
    tagOptions: [
      { label: 'TypeScript', value: 'ts', keywords: ['typed'] },
      { label: 'Accessibility', value: 'a11y' },
      { label: 'Performance', value: 'perf' },
      { label: 'Internal · unavailable', value: 'internal', disabled: true },
    ],
    customAllowed: ref(true),
    duplicatesAllowed: ref(false),
    pending: ref(false),
    locked: ref(false),
    clear: () => selectedTags([requiredTag]),
  }
}

const component = defineComponent<MultiAutoCompleteInputExample>(
  multiAutoCompleteInputExampleTemplate,
  {
    context: createMultiAutoCompleteInputExample,
  },
)
const icons: Record<string, string> = {
  'lucide:loader-circle': lucide_loader_circle,
  'lucide:x': lucide_x,
  'lucide:chevron-down': lucide_chevron_down,
}

createApp(
  {
    components: {
      MultiAutoCompleteInputExample: component,

      ...defineMultiAutoCompleteInputComponents(),
      ...defineFlexComponents(),
      ...defineFormComponents(),
      ...defineButtonComponents(),
      ...defineIconComponents((name) => icons[name] ?? ''),
    },
  },
  {
    selector: 'app#multi-auto-complete-input-demo',
    template: html`<MultiAutoCompleteInputExample />`,
  },
)

Invalid and disabled tokens

Token state can express validation results supplied by your application.

<RegorApp id="multi-auto-complete-input-states-demo" src="./states.ts"/>
import {
  defineIconComponents,
  defineMultiAutoCompleteInputComponents,
  type MultiAutoCompleteItem,
} from '@purestack/ts-components'
import { lucide_chevron_down, lucide_x } from '@purestack/ts-svg-icons'
import { createApp, defineComponent, html, type SRef, sref } from 'regor'

export interface MultiAutoCompleteInputStates {
  recipients: SRef<MultiAutoCompleteItem[]>
}

const multiAutoCompleteInputStatesTemplate = html`<MultiAutoCompleteInput
  id="multi-token-states"
  label="Example recipients"
  :items="recipients"
  placeholder="Add a recipient"
/>`

function createMultiAutoCompleteInputStates(): MultiAutoCompleteInputStates {
  return {
    recipients: sref<MultiAutoCompleteItem[]>([
      { label: 'Required reviewer', value: 'reviewer', disabled: true },
      {
        label: 'Invalid address',
        value: 'invalid',
        invalid: true,
        tone: 'danger',
      },
    ]),
  }
}

const component = defineComponent<MultiAutoCompleteInputStates>(
  multiAutoCompleteInputStatesTemplate,
  {
    context: createMultiAutoCompleteInputStates,
  },
)
const icons: Record<string, string> = {
  'lucide:x': lucide_x,
  'lucide:chevron-down': lucide_chevron_down,
}

createApp(
  {
    components: {
      MultiAutoCompleteInputStates: component,

      ...defineMultiAutoCompleteInputComponents(),
      ...defineIconComponents((name) => icons[name] ?? ''),
    },
  },
  {
    selector: 'app#multi-auto-complete-input-states-demo',
    template: html`<MultiAutoCompleteInputStates />`,
  },
)

Behavior and accessibility

Arrow keys and Enter select suggestions; Escape closes the popup. Backspace on an empty query removes the last removable token. Each selected item produces a hidden field when name is supplied. required applies to the query input, so validate selected items explicitly when requiring at least one token.

API reference

MultiAutoCompleteInput 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
surfaceAlt

Visual treatment. Accepts solid, surface, surfaceAlt, spotlight, glass, flat, flatAlt, flatSolid, outlineFill, outline, subtle, subtleBtn, link, sheen, underline, rail, bracket or none.

items

SRef<MultiAutoCompleteItem[]>
Default
sref([])

Writable shallow ref of MultiAutoCompleteItem[]. Each item supports label, value, disabled, invalid, tone and keywords.

model

Ref<string>
Default
ref('')

Two-way value ref. Pass the ref itself with :model="fieldValue" so edits update application state.

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.

removeIcon

RefOrValue<string>
Default
lucide:x

Registered icon on each removable token button.

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
MultiAutoCompleteOptionRow

Registered row presentation. The input supplies option semantics and keyboard selection.

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.

allowCustomValues

RefOrValue<boolean>
Default
true

Allows Enter and separators to create tokens from query text.

allowDuplicates

RefOrValue<boolean>
Default
false

Allows repeated selected values when true.

separators

RefOrValue<string>
Default
,;

Characters that commit query fragments; newline also splits pasted input.

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.

onCreateItem

RefOrValue<MultiAutoCompleteCreateItem>
Default
not set

Maps query text to a MultiAutoCompleteItem, or null/undefined to reject it.

onOptionToItem

RefOrValue<MultiAutoCompleteOptionToItem>
Default
not set

Maps a resolved suggestion to an item, or null/undefined to reject it.

onSplitInput

RefOrValue<MultiAutoCompleteSplitInput>
Default
not set

Custom text splitter returning string fragments. Replaces default separator splitting.

onItemsChange

RefOrValue<MultiAutoCompleteItemsChange>
Default
not set

Receives the updated selected-item array.

onSelect

RefOrValue<MultiAutoCompleteSelect>
Default
not set

Receives the resolved option and the item created from it.

onSearch

RefOrValue<MultiAutoCompleteSearch>
Default
not set

Callback receiving the query string after an edit. Use it to load or filter application data.

Composition

No slots. Register defineMultiAutoCompleteInputComponents and defineIconComponents. Use sref for items and ref for the current text model.

Events and item data

The input emits itemschange, itemremove, itemcreate, optionselect and querychange. Each item can carry label, value, disabled, invalid, tone and keywords. Keep persistence and domain validation in the owning app.