AutoComplete
Form auto-complete component.
Form Auto Complete, Customization Blocks
Example:
// AppServiceProvider, "boot" method. TallStackUi::customize() ->form('autocomplete') ->block('box.list.item.wrapper', 'your-tailwind-classes');
The autocomplete
is an input-first single-select component: a regular text
input paired with a floating dropdown of suggestions that filters as the user types. Each item
supports a value
, an optional description
shown as a subtitle
line, and an optional image
rendered as a circular avatar to the left.
Free text is allowed by default; an opt-in strict
mode constrains
wire:model
to predefined values only. Items can be supplied locally via
:items
or fetched on demand with :request
.
The component does not support multiple selection. Reach for Select Styled when multiple selection is required.
Provide a list of items via the items
attribute. Each item must have a
value
key, which is both the visible text and the value bound to
wire:model
. Filtering is case-insensitive and runs fully client-side.
<!-- "items" accepts a plain array or a collection instance --> <x-autocomplete :items="[ ['value' => 'São Paulo'], ['value' => 'Rio de Janeiro'], ['value' => 'Belo Horizonte'], ['value' => 'Curitiba'], ['value' => 'Porto Alegre'],]" />
<x-autocomplete label="City" hint="Start typing to filter the list" placeholder="Choose a city" :items="[ ['value' => 'São Paulo'], ['value' => 'Rio de Janeiro'], ['value' => 'Belo Horizonte'], ]" />
<x-autocomplete label="Assignee" :items="[ ['value' => 'Taylor Otwell', 'description' => 'Creator of Laravel'], ['value' => 'Nuno Maduro', 'description' => 'Creator of PestPHP'], ['value' => 'Jess Archer', 'description' => 'Creator of Laravel Prompts'],]" />
<x-autocomplete label="Assignee" :items="[ [ 'value' => 'Taylor Otwell', 'description' => 'Creator of Laravel', 'image' => 'https://unavatar.io/github/taylorotwell', ], [ 'value' => 'Nuno Maduro', 'description' => 'Creator of PestPHP', 'image' => 'https://unavatar.io/github/nunomaduro', ], [ 'value' => 'Jess Archer', 'description' => 'Creator of Laravel Prompts', 'image' => 'https://unavatar.io/github/jessarcher', ],]" />
An option to dim a row and block its selection.
<x-autocomplete label="Status" :items="[ ['value' => 'Pending'], ['value' => 'Approved'], ['value' => 'Rejected', 'disabled' => true],]" />
<x-autocomplete label="City" clearable :items="[ ['value' => 'São Paulo'], ['value' => 'Rio de Janeiro'], ['value' => 'Belo Horizonte'],]" />
<x-autocomplete label="IA" prefix="www" suffix=".com" :items="[ ['value' => 'claude'], ['value' => 'chatgpt'], ['value' => 'gemini.google'], ]" />
The lazy
attribute defines the minimum number of characters the user must
type before the dropdown is allowed to open. Below the threshold the panel stays closed; once
the user crosses it, the panel opens normally.
<x-autocomplete label="City" lazy="2" :items="[ ['value' => 'São Paulo'], ['value' => 'Rio de Janeiro'], ['value' => 'Belo Horizonte'], ['value' => 'Curitiba'], ['value' => 'Porto Alegre'], ['value' => 'Salvador'], ['value' => 'Recife'], ['value' => 'Fortaleza'],]" />
By default, wire:model
reflects whatever the user types, even values that
don't appear in the list. With strict
, the binding only updates when a row
is picked from the dropdown. If the user blurs or presses Esc with an unmatched query, the
input reverts to the last selected value (or empties if nothing was ever picked).
<x-autocomplete label="Status" strict :items="[ ['value' => 'Pending'], ['value' => 'Approved'], ['value' => 'Rejected'],]" />
A global default is available so an entire application can opt every autocomplete into strict mode at once via configuration:
// config/tallstackui.php 'autocomplete' => [ Components\Form\Autocomplete\Component::class, [ /* |---------------------------------------------------------------------- | Autocomplete Global Settings |---------------------------------------------------------------------- | strict: when true, all autocomplete components will, by default, only | accept values that exist in their items list. The wire:model is only | updated when a row is picked from the dropdown, and the input reverts | to the last selected value on blur with an unmatched query. */ 'strict' => false, ],],
Similar to the select.styled
component, the autocomplete can fetch items from a remote endpoint as the user types.
<!-- Using a route as a string --><x-autocomplete label="User" request="/api/users" /> <!-- Using a Laravel route --><x-autocomplete label="User" :request="route('api.users')" />
For finer control, you can pass request
as an array containing: the url
key; also method
which accepts get
or
post
and params
, that is are hydrated on every request,
so reactive Livewire properties placed there stay up to date.
<x-autocomplete label="User" :request="[ 'url' => route('api.users'), 'method' => 'post', 'params' => ['team_id' => 7],]" />
The endpoint must return items shaped the same way as :items
,
value
, optional description
, optional
image
, optional disabled
:
use App\Models\User;use Illuminate\Http\Request;use Illuminate\Support\Facades\Route; Route::get('/users', function (Request $request) { $search = $request->get('search'); return User::query() ->when($search, fn ($query) => $query->where('name', 'like', "%{$search}%")) ->limit(10) ->get() ->map(fn (User $user): array => [ 'value' => $user->name, 'description' => $user->email, 'image' => $user->avatar, ]);})->name('api.users');
The items
and request
attributes are mutually exclusive
and cannot be defined at the same time.
Combine request
with lazy
to avoid firing a request on
every keystroke. The dropdown only opens (and the request only goes out) once the query
crosses the threshold.
<x-autocomplete label="User" request="/api/users" lazy="2" clearable />
<x-autocomplete label="City" disabled :items="[ ['value' => 'São Paulo'], ['value' => 'Rio de Janeiro'],]" />
You can override the translation strings used inside the component. All available keys are
default
(input placeholder), empty
(no results message),
and loading
(remote-source spinner caption).
<x-autocomplete label="User" request="/api/users" :placeholders="[ 'default' => 'Type a user name...', 'empty' => 'No user matches your search.', 'loading' => 'Searching users...', ]" />
An option to rendered inside the dropdown when the filtered list is empty.
<x-autocomplete label="City" :items="[ ['value' => 'São Paulo'], ['value' => 'Rio de Janeiro'],]"> <x-slot:after> <div class="my-2 flex items-center justify-center px-2"> <x-button xs x-on:click="$tsui.interaction('dialog').success('Done!', `Term: ${search}`).send()"> <span x-html="`Create city <b>${search}</b>`"></span> </x-button> </div> </x-slot:after></x-autocomplete>
The component dispatches AlpineJS events for every meaningful interaction. The
select
event payload exposes the picked row at
$event.detail.item
, including any extra keys you put on it.
<!-- $event.detail.item: the picked row, including any extra keys you put on it. --> <x-autocomplete label="User" :items="[ ['value' => 'Alice', 'description' => 'admin'], ['value' => 'Bob', 'description' => 'editor'],]" x-on:select="alert(`Selected: ${$event.detail.item.value}`)" x-on:clear="alert('Cleared')" x-on:open="console.log('opened')" x-on:close="console.log('closed')" />