Livewire 4: Fondasi Utama Aplikasi Web Modern

  • author-image

    Kurnia Andi Nugroho

  • Livewire 4 Livewire Belajar livewire Tutorial livewire 4
  • blog-comment 0 comment
  • dilihat 264 kali
  • 26 Jan, 2026
blog-thumbnail

Form di Livewire 4: Fondasi Utama Aplikasi Web Modern

Kalau kita bicara aplikasi web, hampir bisa dipastikan form adalah tulang punggungnya. Mulai dari login, registrasi, input data, sampai proses checkout—semuanya berputar di sekitar form.

Karena itulah, Livewire 4 memberikan perhatian besar pada urusan form. Bukan hanya soal input sederhana, tapi juga hal-hal yang lebih kompleks seperti validasi real-time, upload file, auto-save, hingga UX yang terasa responsif tanpa JavaScript berlebihan.

Mari kita bahas pelan-pelan, dari yang paling dasar.


Mengirim Form (Submitting a Form)

Kita mulai dari contoh paling sederhana: form tambah post.

<?php // resources/views/components/post/⚡create.blade.php

use Livewire\Component;
use App\Models\Post;

new class extends Component {
    public $title = '';
    public $content = '';

    public function save()
    {
        Post::create(
            $this->only(['title', 'content'])
        );

        session()->flash('status', 'Post berhasil disimpan.');

        return $this->redirect('/posts');
    }
};
?>
<form wire:submit="save">
    <input type="text" wire:model="title">
    <input type="text" wire:model="content">

    <button type="submit">Save</button>
</form>

Di sini ada dua konsep penting:

  1. wire:model Digunakan untuk mengikat input ke property Livewire. Ketika user mengetik, nilainya disimpan ke $title dan $content.
  2. wire:submit Digunakan untuk menangkap event submit dan memanggil method save().

Tanpa AJAX, tanpa controller tambahan—langsung PHP.


Menambahkan Validasi

Form tanpa validasi ibarat pintu rumah tanpa kunci. Livewire 4 mempermudah validasi dengan attribute #[Validate].

use Livewire\Attributes\Validate;

new class extends Component {
    #[Validate('required')]
    public $title = '';

    #[Validate('required')]
    public $content = '';

    public function save()
    {
        $this->validate();

        Post::create(
            $this->only(['title', 'content'])
        );

        return $this->redirect('/posts');
    }
};

Di Blade, kita tampilkan error-nya:

<input type="text" wire:model="title">
@error('title') <span>{{ $message }}</span> @enderror

<input type="text" wire:model="content">
@error('content') <span>{{ $message }}</span> @enderror

Sekarang, jika user men-submit form kosong, Livewire otomatis menampilkan pesan error.

Yang menarik: validasi ini berjalan di server, tapi terasa seperti di client.


Menggunakan Form Object (Struktur Lebih Rapi)

Saat form mulai besar, property dan validasi akan memenuhi komponen. Untuk itulah Livewire menyediakan Form Object.

Buat form dengan Artisan:

php artisan livewire:form PostForm

Hasilnya:

namespace App\Livewire\Forms;

use Livewire\Form;
use Livewire\Attributes\Validate;

class PostForm extends Form
{
    #[Validate('required|min:5')]
    public $title = '';

    #[Validate('required|min:5')]
    public $content = '';
}

Gunakan di komponen:

use App\Livewire\Forms\PostForm;

new class extends Component {
    public PostForm $form;

    public function save()
    {
        $this->validate();

        Post::create(
            $this->form->only(['title', 'content'])
        );

        return $this->redirect('/posts');
    }
};

Di Blade:

<input wire:model="form.title">
@error('form.title') <span>{{ $message }}</span> @enderror

<input wire:model="form.content">
@error('form.content') <span>{{ $message }}</span> @enderror

Dengan pendekatan ini:

  • Komponen lebih bersih
  • Logika form terpusat
  • Bisa dipakai ulang

Memindahkan Logika Simpan ke Form

Form object juga bisa menangani proses simpan:

class PostForm extends Form
{
    #[Validate('required|min:5')]
    public $title = '';

    #[Validate('required|min:5')]
    public $content = '';

    public function store()
    {
        $this->validate();

        Post::create(
            $this->only(['title', 'content'])
        );
    }
}

Komponen jadi sangat ringkas:

public function save()
{
    $this->form->store();

    return $this->redirect('/posts');
}

Form Create & Edit dalam Satu Form Object

Form object sangat cocok untuk create dan edit sekaligus.

class PostForm extends Form
{
    public ?Post $post = null;

    #[Validate('required|min:5')]
    public $title = '';

    #[Validate('required|min:5')]
    public $content = '';

    public function setPost(Post $post)
    {
        $this->post = $post;
        $this->title = $post->title;
        $this->content = $post->content;
    }

    public function update()
    {
        $this->validate();

        $this->post->update(
            $this->only(['title', 'content'])
        );
    }
}

Digunakan di post.edit:

public function mount(Post $post)
{
    $this->form->setPost($post);
}

Reset dan Pull Data Form

Setelah submit, sering kali kita ingin membersihkan form.

$this->reset();
$this->reset('title');
$this->reset(['title', 'content']);

Atau versi ringkas:

Post::create(
    $this->pull()
);

pull() akan mengambil nilai sekaligus meresetnya.


Validasi dengan Rule Object

Untuk kasus validasi kompleks:

use Illuminate\Validation\Rule;

protected function rules()
{
    return [
        'title' => [
            'required',
            Rule::unique('posts')->ignore($this->post),
        ],
        'content' => 'required|min:5',
    ];
}

Dengan pendekatan ini, validasi hanya berjalan saat $this->validate() dipanggil.


Loading Indicator Saat Submit

Livewire otomatis men-disable input saat submit, tapi user tetap butuh feedback visual.

<button type="submit">
    <span class="in-data-loading:hidden">Save</span>
    <span class="not-in-data-loading:hidden">Saving...</span>
</button>

UX jadi jauh lebih jelas dan profesional.


Live Updating Input

<input wire:model.live="title">

Setiap ketikan langsung dikirim ke server. Cocok untuk:

  • live search
  • preview real-time

Alternatif yang lebih hemat:

<input wire:model.blur="title">

Request hanya dikirim saat input kehilangan fokus.


Validasi Real-Time

Dengan .blur atau .live, Livewire otomatis memvalidasi input saat diubah.

#[Validate('required|min:5')]
public $title = '';

User langsung tahu kesalahan tanpa harus submit form.


Auto Save dengan updated()

Untuk fitur auto-save:

public function updated($name, $value)
{
    $this->post->update([
        $name => $value,
    ]);
}

Setiap field disimpan begitu selesai diedit.


Menampilkan Status “Belum Tersimpan”

<input wire:model.blur="title" wire:dirty.class="border-yellow">

Atau:

<div wire:dirty wire:target="title">
    Belum disimpan...
</div>

Ini detail kecil, tapi sangat meningkatkan UX.


Debounce dan Throttle

Debounce (tunggu user berhenti mengetik):

<input wire:model.live.debounce.150ms="title">

Throttle (kirim request tiap interval):

<input wire:model.live.throttle.150ms="title">

Pilih sesuai kebutuhan performa aplikasi.


Menyederhanakan Form dengan Blade Component

Daripada menulis ulang input + error:

<x-input-text name="title" wire:model="title" />
<!-- resources/views/components/input-text.blade.php -->
@props(['name'])

<input type="text" {{ $attributes }}>
@error($name) <span>{{ $message }}</span> @enderror

Form jadi lebih bersih dan konsisten.


Custom Input dengan Alpine + Livewire

Contoh input counter:

<x-input-counter wire:model="quantity" />
<div x-data="{ count: 0 }"
     x-modelable="count"
     {{ $attributes }}>
    <button @click="count--">-</button>
    <span x-text="count"></span>
    <button @click="count++">+</button>
</div>

x-modelable adalah kunci agar Alpine dan Livewire bisa berbagi state.


Penutup

Form di Livewire 4 bukan sekadar input dan submit. Ia adalah sistem yang lengkap:

  • validasi
  • state management
  • UX modern
  • performa terjaga.
author_photo
Kurnia Andi Nugroho

Web & Mobile App Developer, Laravel, Inertia, Vue.Js, React.Js

Founder of Lagikoding.com Laravel Enthusiast & Web Developer