laravel-livewire

Auto-invoked skill

Create Livewire 3 components with forms, tables, modals

Trigger Keywords

This skill automatically activates when Claude detects these keywords:

livewire wire:model reactive component alpine

Overview

The laravel-livewire skill provides expertise for building reactive components with Livewire 3. It covers component lifecycle, forms, validation, real-time updates, and Alpine.js integration.

What This Skill Provides

  • Component Patterns - Forms, tables, modals, wizards
  • Two-way Binding - wire:model, wire:model.live, wire:model.blur
  • Actions - wire:click, wire:submit, events
  • Lifecycle Hooks - mount, hydrate, updated, etc.
  • File Uploads - WithFileUploads trait
  • Pagination - WithPagination trait

Example Conversations

# Building a form
"Create a Livewire form for user registration with real-time validation"

# Data tables
"Build a searchable, sortable data table with pagination"

# Modals
"How do I create a confirmation modal in Livewire 3?"

# Events
"Communicate between two Livewire components"

Livewire 3 Component Example

<?php

namespace App\Livewire;

use App\Models\Post;
use Livewire\Attributes\Rule;
use Livewire\Attributes\Title;
use Livewire\Component;

#[Title('Create Post')]
class CreatePost extends Component
{
    #[Rule('required|min:3')]
    public string $title = '';

    #[Rule('required|min:10')]
    public string $content = '';

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

        Post::create($validated);

        session()->flash('success', 'Post created!');

        $this->redirect(route('posts.index'));
    }

    public function render()
    {
        return view('livewire.create-post');
    }
}

Blade Template

<form wire:submit="save">
    <div>
        <input wire:model.blur="title" type="text">
        @error('title')
            <span class="error"></span>
        @enderror
    </div>

    <div>
        <textarea wire:model.blur="content"></textarea>
        @error('content')
            <span class="error"></span>
        @enderror
    </div>

    <button type="submit">
        <span wire:loading.remove>Save</span>
        <span wire:loading>Saving...</span>
    </button>
</form>

Wire:model Modifiers

Modifier Behavior
wire:model Deferred (on form submit)
wire:model.live Updates on every keystroke
wire:model.blur Updates when field loses focus
wire:model.live.debounce.500ms Debounced live updates

Events Between Components

// Dispatching an event
$this->dispatch('post-created', id: $post->id);

// Listening in another component
#[On('post-created')]
public function handlePostCreated(int $id): void
{
    $this->posts = Post::latest()->get();
}

// From JavaScript
Livewire.dispatch('post-created', { id: 1 })

Common Pitfalls

// 1. Missing wire:key - Always use in loops
@foreach($items as $item)
    <div wire:key="item-">...</div>
@endforeach

// 2. N+1 Queries in render() - Eager load relationships
// BAD
public function render()
{
    return view('livewire.posts', [
        'posts' => Post::all(), // N+1 when accessing $post->author
    ]);
}

// GOOD
public function render()
{
    return view('livewire.posts', [
        'posts' => Post::with('author')->get(),
    ]);
}

// 3. Large Component State - Store IDs, not collections
// BAD
public Collection $products;

// GOOD
public array $productIds = [];

// 4. Not Debouncing Search - Causes excessive requests
// BAD
<input wire:model.live="search">

// GOOD
<input wire:model.live.debounce.300ms="search">

// 5. Forgetting to Reset Pagination
public function updatedSearch(): void
{
    $this->resetPage();
}

// 6. Memory Leaks with File Uploads
public function save(): void
{
    $path = $this->photo->store('photos');
    $this->reset('photo'); // Clear temporary upload
}

Package Integration

  • livewire/livewire - Core framework
  • wire-elements/modal - Modal dialogs
  • rappasoft/laravel-livewire-tables - DataTables
  • livewire/volt - Single-file components

Best Practices

  • Use wire:key for list items
  • Debounce search inputs: wire:model.live.debounce.300ms
  • Use #[Computed] for derived data
  • Keep components focused (single responsibility)
  • Use events for cross-component communication
  • Prefer wire:navigate for SPA-like navigation
  • Use loading states for better UX

Loading States

<!-- Show while any action runs -->
<div wire:loading>Loading...</div>

<!-- Show for specific action -->
<div wire:loading wire:target="save">Saving...</div>

<!-- Disable button while loading -->
<button wire:loading.attr="disabled">Submit</button>

<!-- Add class while loading -->
<div wire:loading.class="opacity-50">Content</div>

Related Commands

Related Agent