Laravel Simple Select
Laravel Simple Select inputs component for Blade and Livewire.
DEMO PREVIEW
Table of Contents
- Laravel Simple Select
Installation
You can install the package via composer:
composer require victorybiz/laravel-simple-select
OPTIONAL: To customize the component, you should publish the configuration file using the vendor:publish Artisan command. The configuration file will be placed in your application's config directory and view file in views directory respectively:
# Publish the config file
php artisan vendor:publish --tag=simple-select:config
# Publish the view file
php artisan vendor:publish --tag=simple-select:views
Requirements
This package use the following packages.
- Laravel Livewire (https://laravel-livewire.com/) is required when using Livewire
wire:model
- TailwindCSS (https://tailwindcss.com/)
- Heroicon (https://heroicons.com/)
- Alpine.js v3 (https://alpinejs.dev/)
- Popper.js (https://popper.js.org/)
Please make sure you include these dependencies before using this component.
JavaScript Dependencies
For any external JavaScript dependency, we recommend you install them through npm or yarn, and then require them in your project's JavaScript. To install each of the dependencies this package makes use of, run this command in the terminal:
npm install -D alpinejs @popperjs/core
import Alpine from 'alpinejs'
import { createPopper } from "@popperjs/core";
window.Alpine = Alpine;
Alpine.start()
window.createPopper = createPopper;
If you’re using the compiled JavaScript, don’t forget to include CDN versions of the JavaScript Dependencies before it.
Usage
Simple Select
@php
// Basic Arrays
$options = ['Nigeria', 'United Kingdom', 'United States'];
// Above will output Option Value e.g Nigeria
// Above will output Option Text e.g Nigeria
// OR
// Associative Arrays
$options = [
['value' => 'NG', 'text' => 'Nigeria'],
['value' => 'GB', 'text' => 'United Kingdom'],
['value' => 'US', 'text' => 'United States']
];
// Above will output Option Value e.g NG
// Above will output Option Text e.g Nigeria
// OR
// Using Associative Arrays data from a Model/Database,
// ensure to customize the field names with value-field="code" and text-field="name" properties of the component.
$options = [
['code' => 'NG', 'name' => 'Nigeria'],
['code' => 'GB', 'name' => 'United Kingdom'],
['code' => 'US', 'name' => 'United States']
];
// OR
$options = [
['code' => 'NG', 'name' => 'Nigeria', 'flag' => 'https://www.countryflags.io/ng/shiny/32.png'],
['code' => 'GB', 'name' => 'United Kingdom', 'flag' => 'https://www.countryflags.io/gb/shiny/32.png'],
['code' => 'US', 'name' => 'United States', 'flag' => 'https://www.countryflags.io/us/shiny/32.png']
];
// Above will output Option Value e.g NG
// Above will output Option Text e.g Nigeria
@endphp
<x-simple-select
name="country"
id="country"
:options="$options"
value-field='code'
text-field='name'
placeholder="Select Country"
search-input-placeholder="Search Country"
:searchable="true"
class="form-select"
/>
Custom Option Slot
<x-simple-select
name="country"
id="country"
:options="$options"
value-field='code'
text-field='name'
placeholder="Select Country"
search-input-placeholder="Search Country"
:searchable="true"
class="form-select"
>
<x-slot name="customOption">
<img class="float-left mr-2 -mt-1" :src="option.flag">
<span x-text="option.name"></span>
</x-slot>
</x-simple-select>
<x-simple-select
name="country"
id="country"
:options="$options"
value-field='code'
text-field='name'
placeholder="Select Country"
search-input-placeholder="Search Country"
:searchable="true"
class="form-select"
>
<x-slot name="customOption">
<img class="float-left mr-2 -mt-1" :src="`https://www.countryflags.io/${option.code?.toLowerCase()}/shiny/32.png`">
<span x-text="option.name"></span>
</x-slot>
</x-simple-select>
Custom Selected Slot
<x-simple-select
name="country"
id="country"
:options="$options"
value-field='code'
text-field='name'
placeholder="Select Country"
search-input-placeholder="Search Country"
:searchable="true"
class="form-select"
>
<x-slot name="customSelected">
<img class="float-left mr-2" :src="`https://www.countryflags.io/${option.code?.toLowerCase()}/shiny/24.png`">
<span x-text="option.name"></span>
</x-slot>
<x-slot name="customOption">
<img class="float-left mr-2 -mt-1" :src="`https://www.countryflags.io/${option.code?.toLowerCase()}/shiny/32.png`">
<span x-text="option.name"></span>
</x-slot>
</x-simple-select>
Custom Icon Slots
<x-simple-select
name="country"
id="country"
:options="$options"
value-field='code'
text-field='name'
placeholder="Select Country"
search-input-placeholder="Search Country"
:searchable="true"
class="form-select"
>
<x-slot name="customOption">
<img class="float-left mr-2 -mt-1" :src="option.flag">
<span x-text="option.name"></span>
</x-slot>
<x-slot name="customDeselectOptionIcon">
<!-- Heroicon solid/x-circle -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class = 'h-4 fill-current'>
<path d="M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm6 16.538l-4.592-4.548 4.546-4.587-1.416-1.403-4.545 4.589-4.588-4.543-1.405 1.405 4.593 4.552-4.547 4.592 1.405 1.405 4.555-4.596 4.591 4.55 1.403-1.416z"/>
</svg>
</x-slot>
</x-simple-select>
Dependent Selects
If you have a custom select whose options depend on the selection of another select, or just some kind of condition to be met, you can listen to the updated event of the livewire model of the main select to update the options in the dependent select.
// Expected data in Database
// Model Country::class
$countries = [
['code' => 'NG', 'name' => 'Nigeria'],
['code' => 'GB', 'name' => 'United Kingdom'],
['code' => 'US', 'name' => 'United States']
];
// Model State::class
$states = [
['id' => 1, 'country_code' => 'NG', 'name' => 'Abuja'],
['id' => 2, 'country_code' => 'NG', 'name' => 'Edo'],
['id' => 3, 'country_code' => 'NG', 'name' => 'Lagos'],
['id' => 4, 'country_code' => 'US', 'name' => 'Alaska'],
['id' => 5, 'country_code' => 'US', 'name' => 'Califonia'],
['id' => 6, 'country_code' => 'US', 'name' => 'Florida'],
['id' => 7, 'country_code' => 'GB', 'name' => 'Belfast'],
['id' => 8, 'country_code' => 'GB', 'name' => 'London'],
// ...
];
Create a livewire component as the form page
<?php
namespace App\Http\Livewire;
use Livewire\Component;
class CreateUser extends Component
{
public $countries = [];
public $states = [];
public $name;
public $country;
public $state;
protected function rules()
{
//
}
public function updated($propertyName)
{
$this->validateOnly($propertyName);
}
public function store()
{
$this->validate();
// Store the data
}
public function mount()
{
$this->countries = \App\Models\Country::orderBy('name')->get()->toArray();
}
public function updatedCountry($countryCode)
{
if ($countryCode) {
$this->states = \App\Models\State::where('country_code', $countryCode)->orderBy('name')->get()->toArray();
} else {
$this->states = [];
}
$this->state = null;
}
public function render()
{
return view('livewire.create-user');
}
}
In your component view
<form wire:submit.prevent="store">
<label for="name">Name</label>
<div class="mt-1">
<input
wire:model="name"
name="name"
id="name"
placeholder="Enter name"
class="form-input"
/>
</div>
<label for="country">Country</label>
<div class="mt-1">
<x-simple-select
wire:model="country"
name="country"
id="country"
:options="$options"
value-field='code'
text-field='name'
placeholder="Select Country"
search-input-placeholder="Search Country"
:searchable="true"
class="form-select"
/>
</div>
<label for="state">State</label>
<div class="mt-1">
<x-simple-select
wire:model="state"
name="state"
id="state"
:options="$states"
value-field='id'
text-field='name'
placeholder="Select State"
search-input-placeholder="Search State"
:searchable="true"
class="form-select"
/>
</div>
</form>
Event Listener
window.addEventListener('select', function(option) {
console.log(option.detail.value); // Select option value(s)
console.log(option.detail.name); // The select element name
console.log(option.detail.id); // The select element ID
});
Positioning
The simple-select component makes use of Popper.js
for positioning the select menu. This should remove the need for fixed positioning the select menu now. In addition to positioning the menu when opened, Popper.js will also re-position the menu as needed when the page is scrolled.
Props / Attributes
Name | Type | Default | Required | Description |
---|---|---|---|---|
id | Integer||String |
Yes | Used to identify the component in events. | |
name | Integer||String |
Yes | Specifies a name for component. | |
options | Array |
Yes | Array of available options: Objects, Strings or Integers. If array of objects, visible text/label will default to option.text and value default to option.value . |
|
value-field | String |
'value' |
No | Array key for option value if options is an associative array. |
text-field | String |
'text' |
No | Array key for option text if options is an associative array. |
value | Array||String||Integer |
null |
No | Presets the selected options. |
placeholder | String |
'Select Option' |
No | Equivalent to the placeholder attribute on a <select> input. |
searchable | Boolean |
true |
No | Show / hide options search input. |
search-input-placeholder | String |
'Search...' |
No | Equivalent to the placeholder attribute on a <input> . |
clearable | Boolean |
false |
No | Enable support for clearable selection. Use only for a non multiple select. |
class | String |
No | Equivalent to the class attribute on a <select> input. |
|
multiple | Boolean |
false |
No | Equivalent to the multiple attribute on a <select> input. This also enable multiple options tagging if set. |
max-selection | Integer |
No | Limit number of allowed selected options. | |
required | Boolean |
false |
No | Equivalent to the required attribute on a <select> input. |
disabled | Boolean |
false |
No | Equivalent to the disabled attribute on a <select> input. |
no-options | String |
'No option data.' |
No | Message to show when options list is empty. |
no-result | String |
'No results match your search.' |
No | Message to show when no option. |
on-select | String |
'select' |
No | Customize event name of an event emitted after selecting an option. |
Slots / Custom Display
Name | Description |
---|---|
customOption | Slot for custom option text template. See example above. |
customSelected | Slot for custom selected template. See example above. |
customDeselectOptionIcon | Slot for custom deselect option icon markup. See example above. |
customCaretDownIcon | Slot for custom caret down icon markup. See example above. |
customCaretUpIcon | Slot for custom caret up icon markup. See example above. |
Events
Name | Listen to | Description |
---|---|---|
Select | select |
Emitted after selecting an option. See example above. |
Testing
composer test
Changelog
Please see CHANGELOG for more information what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security
If you discover any security related issues, please email [email protected] instead of using the issue tracker.
Credits
License
The MIT License (MIT). Please see License File for more information.
Laravel Package Boilerplate
This package was generated using the Laravel Package Boilerplate.