Wirestrap is still in active development

This project is pre-1.0 and may introduce breaking changes at any time without prior notice.

Autocomplete

Text input with a suggestion dropdown and inline ghost text. The suggestion list comes from a Livewire method via wire-options, called once on first focus and cached client-side. If a value is already bound on load, the method is called immediately to resolve it.

Keyboard:

  • to navigate,
  • Tab, Enter or , to confirm,
  • Escape to close.

Basic usage

Declare a method returning a list<string> and pass its name to wire-options. Use icon to add an icon, and floating for a floating label layout.

#[Renderless]
public function getCities(): array
{
    return ['Paris', 'London', 'Berlin'];
}
{{-- Standard --}}
<x-wirestrap::autocomplete
    wire:model="city"
    wire-options="getCities"
    label="City"
    icon="bi-geo-alt"
/>

{{-- Floating label --}}
<x-wirestrap::autocomplete ... floating />

Icon prop

The icon prop accepts any class string from your preferred icon library, or an array of attributes for full control. Custom icon components are also supported, see icon configuration.

Multiple

Add multiple to enable tag mode. wire:model must bind to an array property. Tags are synced via $wire.$set() rather than through the input directly, so wire:model.live has no effect here. Use the live prop instead to trigger a Livewire request on each tag change.

Keyboard: Enter, Tab, or , to add a tag. Backspace on an empty input removes the last tag.

public array $tags = [];
<x-wirestrap::autocomplete
    ...
    wire:model="tags"
    wire-options="getTags"
    multiple
/>

Add live to sync each tag change to Livewire immediately. Without it, tags are deferred until the next Livewire request.

<x-wirestrap::autocomplete ... live />

Options

Options returned by wire-options can be plain strings or structured objects. Plain strings serve as both the stored value and the display label. Structured objects allow a separate label, groups via optgroup, extra CSS via class, and visual prefixes or suffixes via html_prefix / html_suffix. Filtering always matches both label and value. Ghost text only appears when the query matches the start of the value.

// Plain strings: the string is both the stored value and the display label
#[Renderless]
public function getCities(): array
{
    return ['Paris', 'London', 'Berlin'];
}

// Structured objects: separate value, label, and optional fields
#[Renderless]
public function getContacts(): array
{
    return [
        [
            'value' => '[email protected]',
            'label' => 'Alice Martin',
            'optgroup' => 'Recent',
            'html_prefix' => '<span class="badge badge-primary me-2">Client</span>',
        ],
        [
            'value' => '[email protected]',
            'label' => 'Frank Miller',
            'optgroup' => 'All',
            'html_prefix' => '<span class="badge badge-warning me-2">Partner</span>',
        ],
        // ...
    ];
}
{{-- value = email, label = contact name; search works on both --}}
<x-wirestrap::autocomplete
    wire:model="contact"
    wire-options="getContacts"
    label="To"
    icon="bi-person"
/>

{{-- Multiple mode: tags display the label, the stored value is the email --}}
<x-wirestrap::autocomplete
    wire:model="contacts"
    wire-options="getContacts"
    label="To"
    icon="bi-people"
    multiple
    floating
/>

Dynamic options

Use wire-options-watch to invalidate the cache when a Livewire property changes. Pass a string for cache invalidation only. Pass an array [property, resetValue] to also reset the model on change. To pass arguments to the method, use the array form of wire-options: [method, ...params]. Use ['ws-wire' => 'dotPath'] to resolve a Livewire property at call time. To force a reload imperatively, use $wirestrap.autocomplete.refresh(id).

Category
Select an option
<x-wirestrap::select
    ...
    wire:model="reactiveCategory"
    wire-options="getReactiveCategories"
/>

<x-wirestrap::autocomplete
    ...
    wire:model="reactiveItem"

    {{-- Pass $this->reactiveCategory at call time --}}
    :wire-options="['getReactiveItems', ['ws-wire' => 'reactiveCategory']]"

    {{-- On category change: refresh suggestions and set $this->reactiveItem to null --}}
    :wire-options-watch="['reactiveCategory', null]"
/>

Disabled

<x-wirestrap::autocomplete ... disabled />

Validation

The component checks $errors for the wire:model key and applies the invalid state if found. Try submitting without typing a city.

{{-- Suppress both the invalid class and the error message --}}
<x-wirestrap::autocomplete ... :has-validation="false" />

{{-- Keep the invalid class, hide the error message --}}
<x-wirestrap::autocomplete ... :has-validation-message="false" />

In multiple mode, individual invalid tags are highlighted. Enter any value that is not a valid email address to trigger a per-tag error.

Clipping

The dropdown uses position: absolute by default, which means it can be clipped by a parent with overflow: hidden or confined to a CSS stacking context. Two escape hatches are available:

  • teleport="body" moves the dropdown outside the component's DOM tree entirely to the given selector, via Livewire's @teleport directive. It escapes all stacking contexts and still uses absolute positioning relative to the target, so there is no viewport recalculation on scroll. This is the recommended approach.
  • position="fixed" positions the dropdown relative to the viewport, which escapes most clipping scenarios but not all. Every scroll event while the dropdown is open triggers a viewport recalculation. Prefer teleport unless you have a reason to avoid moving the dropdown in the DOM.
{{-- Default: absolute positioning --}}
<x-wirestrap::autocomplete ... />

{{-- Escape most clipping scenarios, at the cost of viewport recalculations --}}
<x-wirestrap::autocomplete ... position="fixed" />

{{-- Move the dropdown outside the DOM tree entirely, escaping all stacking contexts --}}
<x-wirestrap::autocomplete id="my-autocomplete" ... teleport="body" />

Props

Global configuration

Most prop defaults can be overridden globally via config/wirestrap.php.

x-wirestrap::autocomplete

Prop Type Default Description
id string|null null Input id. Auto-resolved from wire:model when omitted.
label ComponentSlot|string|null null Label text or slot content. No label element is rendered when null.
wire-options string|list<mixed>|null null Livewire method returning the suggestions array — see Option definition below. String: method name. Array: [method, ...params] — remaining elements are passed as positional arguments; use ['ws-wire' => 'dotPath'] to resolve a Livewire property at call time. Called once on first focus and cached client-side.
wire-options-watch string|list<mixed>|null null Livewire property to watch. Invalidates the cache on change; reloads on next focus or immediately if open. Array form [property, resetValue] also resets the model on change; third element true triggers a server round-trip on reset. Requires wire-options.
icon string|array null Icon identifier forwarded to the configured icon component.
icon-placement string 'start' Icon position: start or end.
placeholder string|null null Placeholder text. Forced to a space in floating mode.
floating bool false Use floating label layout.
min-chars int config Minimum number of characters required before suggestions appear. 0 shows all suggestions on focus.
no-dropdown bool config Disable the suggestion dropdown entirely. Useful in multiple mode as a pure tag input with no suggestions.
multiple bool false Enable tag mode. wire:model must bind to an array property.
live bool false In multiple mode, sync to Livewire on each tag change instead of deferring.
disabled bool false Disable the component.
has-validation-message bool config Render the error message below the field.
has-validation bool config Apply the invalid class when the wire:model key has an error.
default-attributes array config Default HTML attributes merged onto the input element.
dropdown-offset int config Y-axis offset in pixels between the trigger and the dropdown.
position string config Dropdown positioning strategy: absolute or fixed. See Clipping.
teleport string|null config CSS selector of the teleport target (e.g. body). Moves the dropdown outside the component's DOM tree, escaping all stacking contexts. Requires id. See Clipping.
No results

Option definition

Prop Type Default Description
value string -- The value stored and injected into the input on selection.
label string '' Display text. Always rendered as plain text. Filtering matches both label and value.
optgroup string null Group label. Options sharing the same value are rendered together. Options without optgroup appear after all groups.
class string null Extra CSS class applied to the option element and the tag in multiple mode.
html_prefix string null Raw HTML injected before the label. Never pass user-generated content without escaping it first.
html_suffix string null Raw HTML injected after the label. Same XSS warning applies.
No results

$wirestrap.autocomplete

Method Type Default Description
$wirestrap.autocomplete.refresh(id) -- -- Invalidate the cached list and call wire-options immediately. id is the input id (auto-resolved from wire:model when omitted).
No results