Selects
The x-select
component is a powerful, customizable dropdown:
Supports icons/avatars per option, multi-select, clearable fields, async/remote search, lazy loading/infinite scroll, validation and more.
All features can be combined seamlessly for advanced UX.
You can customize this component
Basic Usage
Basic Usage
- Pass a plain array, an array of objects, or an Eloquent-like collection to
:options
. - Each option can define: label, icon, avatar, description, etc.
- Single selection by default.
blade
1<x-select :options="['Option 1', 'Option 2', 'Option 3']" label="Simple array" clearable /> 2 3<x-select 4 :options="[ 5 ['id' => 1, 'label' => 'Option A', 'icon' => '⭐'], 6 ['id' => 2, 'label' => 'Option B', 'icon' => '🌵'], 7 ['id' => 3, 'label' => 'Option C', 'icon' => '🎯'], 8 ]" 9 label="Object array"10 clearable11/>12 13<x-select :options="$categories" label="Categories" placeholder="Choose a category..." clearable />14 15<x-select :options="[16 ['id' => 1, 'label' => 'Frontend', 'avatar' => 'https://randomuser.me/api/portraits/men/5.jpg'],17 ['id' => 2, 'label' => 'Backend', 'avatar' => 'https://randomuser.me/api/portraits/women/22.jpg'],18 ['id' => 3, 'label' => 'Mobile', 'avatar' => null],19]" label="With avatars" clearable />
Multi-Select, Search, Clearable
- multiple: allows multi-selection (returns array).
- clearable: adds an X to remove selection.
- searchable: enables input to filter options (works local/remote).
blade
1<x-select :options="$categories" label="Categories" multiple clearable />2<x-select :options="$categories" label="Categories (search)" searchable />3<x-select :options="$categories" label="Multi search" multiple searchable clearable />
Option Features: Icons, Avatars, Descriptions
- Each option can have an icon (SVG, emoji, string), avatar (image), and/or description (below label).
blade
1<x-select :options="[2 ['id'=>1, 'label'=>'Design', 'avatar'=>'https://randomuser.me/api/portraits/men/5.jpg', 'description'=>'UI/UX'],3 ['id'=>2, 'label'=>'Development', 'avatar'=>'https://randomuser.me/api/portraits/women/22.jpg', 'description'=>'Backend/Frontend'],4 ['id'=>3, 'label'=>'Marketing', 'icon'=>'💼', 'description'=>'SEO/Content'],5 ['id'=>4, 'label'=>'🤖 Bot', 'icon'=>'🤖'],6]" label="Icons/avatars/desc" clearable />
Remote/Async & Lazy Loading
- remote + remote-url: fetch options from any API endpoint.
- lazy: infinite scroll, loads more as you scroll (local or remote).
- For remote endpoints, response should be
{ id: { label, ... } }
or{ options: {...}, hasMore: bool }
.
blade
1<x-select2 remote3 remote-url="{{ route('api.countries.select.lazy') }}"4 label="Lazy country"5 placeholder="Search country..."6 lazy7 searchable8/>
Presets & Colors
- Use Tailwind-style color presets as props, or customize your own.
blade
1<x-select :options="$categories" label="Default" />2<x-select :options="$categories" blue label="Blue" />3<x-select :options="$categories" emerald label="Emerald" />4<x-select :options="$categories" indigo label="Indigo" />5<x-select :options="$categories" rose label="Rose" />6<x-select :options="$categories" amber label="Amber" />7<x-select :options="$categories" cyan label="Cyan" />8<x-select :options="$categories" violet label="Violet" />
Filled
- Use Tailwind-style color presets as props, or customize your own.
blade
1<x-select fill :options="$categories" label="Default" />2<x-select fill :options="$categories" blue label="Blue" />3<x-select fill :options="$categories" emerald label="Emerald" />4<x-select fill :options="$categories" indigo label="Indigo" />5<x-select fill :options="$categories" rose label="Rose" />6<x-select fill :options="$categories" amber label="Amber" />7<x-select fill :options="$categories" cyan label="Cyan" />8<x-select fill :options="$categories" violet label="Violet" />
Validation & Error States
Validation with Livewire
- Works perfectly with
wire:model
for Livewire validation. - Shows red border and error message automatically if validation fails.
- Multi-select returns array, single-select returns value.
You must select a category
blade
1// In your Livewire component: 2public $selectedCategory = null; 3protected $rules = ['selectedCategory' => 'required']; 4 5<x-select 6 :options="$categories" 7 label="Category" 8 wire:model="selectedCategory" 9 clearable10/>
Async Controller Examples
Async Controller with Lazy Loading
Example for async controller with lazy loading support (infinite scroll).
Tip: For large lists, always implement
Tip: For large lists, always implement
hasMore
.
php
1// routes/web.php 2Route::get('/api/country/select', [CountrySelectLazyController::class, 'index'])->name('api.countries.select.lazy'); 3 4// app/Http/Controllers/CountrySelectLazyController.php 5<?php 6 7namespace App\Http\Controllers; 8 9use App\Models\Country;10use Illuminate\Http\Request;11 12class CountrySelectLazyController extends Controller13{14 public function index(Request $request)15 {16 $q = $request->input('q');17 $page = (int) $request->input('page', 1);18 $perPage = (int) $request->input('per_page', 20);19 20 $query = Country::query();21 22 if ($q) {23 $query->where(function ($sub) use ($q) {24 $sub->whereRaw('LOWER(name) LIKE ?', ['%' . strtolower($q) . '%']);25 });26 }27 28 $total = $query->count();29 30 $countries = $query31 ->orderBy('country')32 ->offset(($page - 1) * $perPage)33 ->limit($perPage)34 ->get()35 ->mapWithKeys(function ($country) {36 return [37 $country->id => [38 'label' => $country->name,39 ]40 ];41 });42 43 $hasMore = ($page * $perPage) < $total;44 45 return response()->json([46 'options' => $countries,47 'hasMore' => $hasMore,48 ]);49 }50 51}
Code highlighting provided by Torchlight