@wikicasa-dev/components · Forms · preferred

ClearableAutocomplete

Unstyled search-as-you-type input with an inline clear button, loading slot and race-safe async results.

import ClearableAutocomplete from "@wikicasa-dev/components/UIKit/Autocomplete/ClearableAutocomplete";

Use for any search-as-you-type field: the place search ("Cerca comune, zona o indirizzo") in a hero or header, or a field in a form, where you style the trigger yourself. It is a bare <input> with no label, border or validation: you supply the look through class props and slots. After a selection, a clear button appears right after the typed text.

It is the search-as-you-type component for every case, forms included: style the trigger to match the other fields of the form. It replaces the legacy BaseAutocomplete.

onInputChangeCb(query) runs 300 ms after typing stops and must resolve to { id, label }[]; stale responses are discarded automatically. v-model is the selected option, or null. v-model:inputValue is the raw text; v-model:open the list state.

Usage

<script setup lang="ts">
import { ref } from "vue";
import ClearableAutocomplete from "@wikicasa-dev/components/UIKit/Autocomplete/ClearableAutocomplete";
import type { AccessibleSelectOptions } from "@wikicasa-dev/components";

type Place = AccessibleSelectOptions<{ province: string }, number>;

const PLACES: Place[] = [
  { id: 1, label: "Milano", province: "MI" },
  { id: 2, label: "Milano Marittima", province: "RA" },
  { id: 3, label: "Monza", province: "MB" },
];
// Mock search: replace with your data source
const searchPlaces = async (q: string) =>
  PLACES.filter((p) => p.label.toLowerCase().startsWith(q.toLowerCase()));

const place = ref<Place | null>(null);
</script>

<template>
  <ClearableAutocomplete
    v-model="place"
    placeholder="Cerca comune, zona o indirizzo"
    :on-input-change-cb="searchPlaces"
    trigger-wrapper-classes="search-trigger"
    :clear-button="{ offset: 10 }"
  >
    <template #option-content="{ option }">
      {{ option.label }} <small>({{ option.province }})</small>
    </template>
    <template #loading-state>
      <li style="padding: 10px 20px">Caricamento…</li>
    </template>
  </ClearableAutocomplete>
</template>

Do / Don't

  • Do always set placeholder: the input has no label, so the placeholder is the only text that tells users (and screen readers) what to type.
  • Do style the field via triggerWrapperClasses (row containing icons + input), inputWrapperClasses, inputClasses and dropdownClasses; put icons in left-icon / right-icon and a custom clear glyph in clear-icon (default "X").
  • Do use onOptionSelectedCb(option, { trigger }) to react to a choice; trigger is "click" or "enter".
  • Do call the exposed clearSuggestions() when you hide (not unmount) the component, and focus() / select() to move focus into it.
  • Do set :enable-keyboard-controller="false" only if a parent handles arrow keys itself.
  • Don't call a real API in mockups; use a mock function like the one above.
  • Don't expect aria-* or other attributes to reach the <input>: only class is forwarded (to the root).

Styling hooks

  • .uikit-clearable-autocomplete: --input-padding and --input-margin (both 0) for the <input>.
  • .uikit-clear-btn { --bg-color } (default transparent); also clearButton.classes, width, height, offset (gap after the text, px).
  • The list uses BaseDropDown's .uikit-dropdown-content variables (--dropdown-max-height, borders, radii).

API

Generated from the component's types. Do not edit by hand.

Props

Name Type Default Required Description
dataCy string
placeholder string
enableKeyboardController boolean true
triggerWrapperClasses ClassTypeProp
inputWrapperClasses ClassTypeProp
inputClasses ClassTypeProp
hiddenTextClasses ClassTypeProp
dropdownClasses ClassTypeProp
clearButton { classes?: ClassTypeProp; offset?: number | undefined; width?: number | undefined; height?: number | undefined; dataCy?: string | undefined; }
keepState Nullable<"open" | "closed">
disableCb boolean false
onInputChangeCb (v: string) => Promise<AccessibleSelectOptions<TPayload, TID>[]> yes
onOptionSelectedCb Nullable<(v: AccessibleSelectOptions<TPayload, TID>, meta: ClearableAutocompleteSelectionMeta) => void>
open boolean false
modelValue Nullable<AccessibleSelectOptions<TPayload, TID>> null
inputValue string ""

Events

Name Payload
input [InputEvent]
click [MouseEvent]
keydown [KeyboardEvent]
inputClick [MouseEvent]
update:modelValue [value: Nullable<AccessibleSelectOptions<TPayload, TID>>]
update:open [value: boolean]
update:inputValue [value: string]

v-model

  • v-model:open (boolean)
  • v-model binds modelValue (Nullable<AccessibleSelectOptions<TPayload, TID>>)
  • v-model:inputValue (string)

Slots

Name Slot props
left-icon
clear-icon
right-icon
loading-state
option-content { option: AccessibleSelectOptions<TPayload, TID>; idx: number; }

Exposed (template ref)

None.