Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Livewire Searchable Select Laravel Package

fabioguin/livewire-searchable-select

fabioguin/livewire-searchable-select adds a Livewire-powered searchable select component to Laravel apps, letting users filter long option lists as they type. It simplifies building responsive, searchable dropdowns in Blade/Livewire forms and improves UX when choosing from large datasets.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install the component:
    composer require fabioguin/livewire-searchable-select:^2.0.1
    
  2. Publish the config and views if you intend to restyle the dropdown (most installs can skip this — but see the upgrade note in Gotchas if you already published them):
    php artisan vendor:publish --provider="FabioGuin\LivewireSearchableSelect\LivewireSearchableSelectServiceProvider"
    
  3. Drop the component into a form and bind it like any other Livewire input:
    <livewire:searchable-select
        wire:model="selectedUserId"
        :options="$users"
        searchable
        placeholder="Search users..."
    />
    

Where to look first

  • The Livewire component class — it owns searchTerm, the filtered option list, and the isSelected flag that v2.0.1 introduces guards around.
  • The Blade view — this is where the Alpine bindings live (x-model="$wire.searchTerm" as of this release). If you plan to customise styling, this is the file you'll touch.
  • The config file — controls debounce timing, minimum search length, and default option rendering.

First use case to validate

Pick a single "assign user to team" field and confirm three behaviours end-to-end: typing filters the list, clicking the input again does not clear what you typed, and selecting an option closes the dropdown and clears the search term. Those three are precisely what v2.0.1 fixed, so they make a good smoke test before you roll the package out further.

Alpine note: on Livewire 3 nothing extra is required (Alpine ships with Livewire). On Livewire 2, ensure Alpine is loaded before Livewire's scripts — the x-model binding to $wire.searchTerm depends on the Livewire magic property being available when Alpine initialises.

Implementation Patterns

Server-side search with debounce

Bind the search term on the component and let it filter server-side when the dataset is large:

public string $searchTerm = '';

public function updatedSearchTerm(): void
{
    $this->options = User::query()
        ->where('name', 'like', "%{$this->searchTerm}%")
        ->limit(25)
        ->get()
        ->toArray();
}

Keep the debounce in the config rather than adding wire:model.live.debounce yourself — the component already owns the request cadence, and stacking a second debounce on searchTerm produces duplicate round-trips.

Form integration and validation

Treat the component like a native input for validation purposes: wire:model sets a plain public property, so $this->validate(['selectedUserId' => 'required|exists:users,id']) works unchanged. For long forms, use wire:model (deferred) on the selection and allow searchTerm to update live — the search term is transient and shouldn't trigger validation.

Resetting the field programmatically

After a successful submit, clear both the selection and the search state:

$this->reset('selectedUserId');
$this->dispatch('searchable-select-reset');

Calling $wire.set('searchTerm', '') from Alpine is also valid, but prefer the server-side reset so the dropdown's isSelected state is recalculated in the same render.

Custom option rendering

Publish the views and extend the option partial to include avatars, secondary text, or badges. Keep the wire:key on each option tied to the option's ID so Livewire can diff filtered lists correctly when the search term changes.

Testing

Livewire::test(SearchableSelect::class)->set('searchTerm', 'jane')->assertSee('Jane Doe') covers the filtering path. Add an assertion that searchTerm survives a click on an already-selected option — that's the regression v2.0.1 fixed, and it's cheap to lock in.

Gotchas and Tips

  • Re-publish your views after upgrading. If you published the component view in a previous version, your copy still contains the old Alpine markup and none of the v2.0.1 fixes will apply. Diff your published view against the vendor one before assuming the upgrade "didn't work". This is the single most likely reason for a post-upgrade bug report.
  • Don't mirror searchTerm into a local Alpine variable. The old bug came from two sources of truth. v2.0.1 binds x-model directly to $wire.searchTerm; if you have custom markup that does x-data="{ searchTerm: @entangle('searchTerm') }", remove it or you reintroduce the desync the release just eliminated.
  • The dropdown now closes itself after selection. Any custom JavaScript you wrote to toggle the dropdown on select will now double-fire — you'll see a flicker or a dropdown that refuses to stay open. Delete your close handler and let the component manage it.
  • Preserve the isSelected guard when merging custom click handlers. The fix that stops the search term being wiped when you click an input with an active selection lives in the click handler. If you've forked that handler to add analytics or custom events, re-apply the isSelected check after upgrading.
  • Debugging desync: in the browser console, $wire.searchTerm shows the authoritative server value. If the input's visible text and that value disagree, you have an Alpine binding problem (usually a stale published view), not a Livewire one. The Livewire devtools payload inspector confirms whether searchTerm is being sent on each request.
  • wire:ignore in modals is a trap. Wrapping the component in wire:ignore to protect it from modal re-renders also blocks the $wire.searchTerm updates this release depends on. Use wire:key scoped to the modal instance instead.
  • Watch the Livewire/Alpine version pairing. The $wire magic property in x-model requires a Livewire version that exposes it (Livewire 3, or Livewire 2 with the Alpine integration in place). A mismatched pair produces a silently empty search box rather than an error.
  • Extension point worth knowing: the component's filtered-options method is the natural override if you need scoped queries (tenant filtering, permission-scoped lists). Subclass the component and override it rather than filtering in the Blade view — the view-level approach breaks keyboard navigation ordering.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console