For the past couple of months, I've been working on building a simple CMS web app using Laravel with Livewire 3. While everything was going smoothly, I encountered an issue that left me frustrated—my Select2 dropdown wasn't updating or binding data correctly in Livewire.
📌 Why Use Select2?
I chose Select2 because I needed a simple UI component for searching through a list of data within a dropdown. Select2 provides an elegant solution that enhances standard elements with search functionality, without requiring me to build a custom UI from scratch.
However, integrating Select2 with Livewire 3 wasn’t as straightforward as I expected. The problem? Livewire doesn’t automatically recognize updates made by JavaScript-based components like Select2.
🚨 The Issue: Select2 and Livewire Data Binding
When using Livewire, form inputs are usually bound using wire:model
, allowing real-time updates to the component state. However, since Select2 manipulates the DOM using JavaScript, Livewire doesn’t detect changes made by Select2 unless explicitly notified.
here my basic setup
Blade Component (example.blade.php)
class="max-w-sm mx-auto mb-5" wire:submit.prevent="submit">
for="countries" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Select an option
id="countries" wire:model.live="select_value" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
selected>Choose a country
value="US">United States
value="CA">Canada
value="FR">France
value="DE">Germany
class="mt-2 block mb-2" wire:model="select_value">
type="submit" class="text-white bg-blue-700 px-5 py-2 rounded-md">Save
function init_select2(){
var ctr = $('#countries')
ctr.select2();
}
$(document).ready(function (){
// init_select2();
});
Livewire Component (Example.php)
namespace App\Livewire;
use Livewire\Component;
class Example extends Component
{
public $select_value = "default-value";
public function render()
{
return view('livewire.example');
}
public function submit(){
dd($this->select_value);
}
}
to be able use select2 and jquery, you must include this section on your blade layout
<span class="na">src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js">
href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/select2.min.css" rel="stylesheet" />
<span class="na">src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/select2.min.js">
the code above I do comment on section init select2 and select2 should not be active or running.
here the expected result I need and this is without use select2
you see after click save
button I can see result the value I selected. lets turn on and init select2 by uncomment init_select2();
you can see the result still default-value
and not binding based on value select we are selected.
✅ The Solution: Manually Dispatching Events to Livewire
Since Livewire 3 doesn’t automatically detect DOM changes from JavaScript-based UI components, we need to manually update Livewire’s state when Select2 changes.
Livewire Component (Example.php)
namespace App\Livewire;
use Livewire\Attributes\On;
use Livewire\Component;
class Example extends Component
{
public $select_value = "default-value";
public function render()
{
return view('livewire.example');
}
public function submit(){
dd($this->select_value);
}
#[On('select-updated')]
public function updateValue($val){
$this->select_value = $val;
$this->dispatch("update-value");
}
}
Blade Componenet (example.blade.php
class="max-w-sm mx-auto mb-5" wire:submit.prevent="submit">
for="countries" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Select an option
id="countries" wire:model="select_value" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
selected>Choose a country
value="US">United States
value="CA">Canada
value="FR">France
value="DE">Germany
class="mt-2 block mb-2" wire:model="select_value">
class="block text-sm mb-2">value selected: {{ $select_value }}
type="submit" class="text-white bg-blue-700 px-5 py-2 rounded-md">Save
function init_select2(){
var ctr = $('#countries')
ctr.select2();
}
$(document).ready(function (){
init_select2();
$('#countries').on("change", function (e){
window.Livewire.dispatch('select-updated', [$(this).val()]);
});
});
Livewire.on("update-value", function (){
setTimeout(init_select2, 0)
console.log("event udpated and reset select2")
})
🔍 Key Fixes & Takeaways
✅ Manually dispatch the select-updated
event when Select2 changes.
✅ Listen for update-value
in Livewire to trigger a reinitialization of Select2.
✅ Use setTimeout(init_select2, 0);
to prevent Select2 from breaking after a Livewire re-render. setTimeout
is needed because it ensures that Livewire processes its updates first before re-initializing Select2.
Now, every time a user selects an option, Livewire correctly updates its state, and Select2 remains functional after re-renders! 🚀
here the result
🎯 Final Thoughts
Integrating Select2 with Livewire 3 can be frustrating, but the solution is simple once you understand how Livewire handles JavaScript-based components. By manually dispatching updates and re-initializing Select2, you can enjoy the benefits of Livewire’s reactivity and Select2’s powerful search features.
If you run into issues, try this approach and let me know how it works for you! 🚀🔥