Menggabungkan Livewire dengan Alpine.js: menggunakan x-data, x-show, dan transisi untuk micro-interactions, membangun modal dan dropdown tanpa state server, serta mengakses komponen Livewire lewat objek $wire dari ekspresi Alpine.

Sejak episode-episode awal kita menyebut bahwa Livewire membundel Alpine.js — dan inilah saatnya berkenalan. Alpine adalah JavaScript minimal (sekitar 15KB) yang memberi kemampuan reaktivitas ringan di DOM: menunjukkan/menyembunyikan elemen, transisi, dan state lokal. Ia bukan pengganti Livewire, melainkan pelengkap.
Pembagian kerja yang jelas: Livewire mengelola state dan logika yang hidup di server (data, validasi, query), sedangkan Alpine mengelola hal-hal yang murni visual dan sesaat (apakah dropdown terbuka, apakah modal tampil, animasi). Menempatkan state visual di server adalah kesalahan umum — modal yang terbuka seharusnya tidak butuh round-trip ke server.
<div x-data="{ open: false }">
<button type="button" @click="open = !open">Menu</button>
<div x-show="open" @click.outside="open = false">
<a href="#">Profil</a>
<a href="#">Pengaturan</a>
</div>
</div>x-data="{ open: false }" mendeklarasikan state lokal Alpine.@click (alias x-on:click) memanipulasi state.x-show mengontrol visibilitas; @click.outside menutup dropdown saat klik di luar.Semua ini murni di client — tidak ada request ke server. Inilah pola yang benar untuk interaksi visual sesaat.
Modal adalah kasus paling umum. Di dalam komponen Livewire:
<div x-data="{ show: false }">
<button type="button" wire:click="delete" @click="show = true">
Hapus
</button>
<div x-show="show" class="fixed inset-0 bg-black/50" @click="show = false"></div>
<div x-show="show" role="dialog">
<h2>Yakin ingin menghapus?</h2>
<button type="button" @click="show = false">Batal</button>
<button type="button" @click="show = false; $wire.deleteConfirmed()">Ya, hapus</button>
</div>
</div>Perhatikan campurannya: wire:click untuk aksi server (delete), @click untuk state visual (show). Saat user menekan "Ya, hapus", Alpine menutup modal lalu memanggil $wire.deleteConfirmed() — action Livewire dari dalam ekspresi Alpine.
$wire adalah jembatan dari Alpine ke komponen Livewire. Dari ekspresi Alpine, $wire memberi akses ke:
$wire.deleteConfirmed(), $wire.save()$wire.search, $wire.title = 'baru'<button type="button" @click="$wire.refreshStats()">Muat ulang statistik</button>Ini berguna saat aksi perlu dipicu dari logika Alpine yang kompleks (setelah animasi selesai, setelah kondisi tertentu terpenuhi), bukan langsung dari klik.
Alpine menyediakan x-transition untuk animasi masuk/keluar:
<div x-show="show" x-transition.opacity.duration.200ms>
<!-- isi modal -->
</div><div
x-show="show"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-2"
x-transition:enter-end="opacity-100 translate-y-0"
>
Post berhasil disimpan.
</div>Animasikan kemunculan dan kehilangan — transisi yang baik menandakan elemen muncul dan menghilang secara konsisten.
Kombinasi Livewire + Alpine untuk notifikasi setelah aksi server:
use Livewire\Attributes\On;
#[On('toast')]
public function toast(string $message)
{
$this->js("showToast('{$message}')");
}<script>
function showToast(message) {
const el = document.getElementById('toast');
el.textContent = message;
el.classList.remove('hidden');
setTimeout(() => el.classList.add('hidden'), 2500);
}
</script>Di sini $this->js() (dibahas di episode 18) menjalankan JavaScript di client setelah aksi server selesai. Event + $wire + $this->js() adalah toolkit lengkap untuk feedback yang halus.
Note
Aturan pemilihan yang harus diingat: Jika state-nya perlu diketahui server → Livewire. Jika hanya memengaruhi tampilan di browser itu sendiri → Alpine. Memindahkan dropdown yang sedang terbuka ke public property Livewire berarti tiap buka-tutup mengirim request — boros dan terasa lambat.
@click.outside: dropdown tidak menutup saat klik di luar — UX yang menjengkelkan.$wire tanpa alasan: jika tombolnya langsung, wire:click lebih ekspresif. $wire untuk kasus yang butuh logika Alpine.x-data dengan morphing: pastikan x-data berada di elemen yang distabilkan wire:key saat ada di dalam loop.Inti yang harus dibawa pulang:
x-data, x-show, @click); Livewire menangani state server.x-data + x-show + @click.outside, tanpa request server.$wire menjembatani Alpine ke komponen: panggil action, baca/ubah property.x-transition untuk animasi masuk-keluar yang konsisten.$this->js().Di episode 16 selanjutnya kita akan membahas loading, polling & offline states — wire:loading dan wire:target untuk spinner/skeleton, wire:poll untuk auto-refresh, serta indikator offline agar aplikasi tidak membisu saat koneksi terputus. Sampai jumpa di episode 16!