Slate

Livewire

Slate works with Laravel Livewire out of the box — wire:model, validation errors, loading states, and Alpine overlays all play nicely together.

Installation

terminal
composer require livewire/livewire
composer require electrik/slate

Buttons and actions

example.blade.php
{{-- resources/views/livewire/counter.blade.php --}}
<div>
    <x-slate::button wire:click="increment">
        Count: {{ $count }}
    </x-slate::button>
</div>

Form controls

Progressive props (label, description, errorMessage) compose the field helpers automatically. Livewire validation keys are detected from wire:model / name.

example.blade.php
<form wire:submit="save" class="grid max-w-md gap-4">
    <x-slate::input
        label="Name"
        wire:model="name"
        description="How you appear on invoices."
    />

    <x-slate::textarea
        label="Bio"
        wire:model.blur="bio"
    />

    <x-slate::select label="Country" wire:model="country">
        <option value="us">United States</option>
        <option value="uk">United Kingdom</option>
    </x-slate::select>

    <x-slate::checkbox
        label="Subscribe"
        description="Product updates only."
        wire:model="subscribe"
    />

    <x-slate::button type="submit" wire:loading.attr="disabled">
        <span wire:loading.remove>Save</span>
        <span wire:loading>Saving…</span>
    </x-slate::button>
</form>

Or let Slate handle the busy UI when you use wire:click / wire:submit with loading-text:

example.blade.php
<x-slate::button wire:click="save" loading-text="Saving…">
    Save
</x-slate::button>

For static docs demos (no Livewire), use the loading prop or Alpine — see Button.

Toast from Livewire

Mount <x-slate::toaster /> once in your layout, then dispatch a browser event after an action:

example.php
// app/Livewire/ProfileForm.php
public function save(): void
{
    $this->validate();
    // ...

    $this->dispatch('slate-toast',
        title: 'Saved',
        description: 'Your profile was updated.',
        variant: 'success',
    );
}

Livewire v3 browser events bubble as slate-toast with a detail payload — the toaster listens on window.

You can also listen in Alpine:

example.blade.php
<div @@slate-toast.window="console.log($event.detail)">
    
</div>

Dialogs and sheets

Keep Alpine state on the Slate root; call Livewire from actions inside:

example.blade.php
<x-slate::dialog>
    <x-slate::dialog-trigger>
        <x-slate::button variant="outline">Delete account</x-slate::button>
    </x-slate::dialog-trigger>

    <x-slate::dialog-content title="Are you sure?" description="This cannot be undone.">
        <x-slot:footer>
            <x-slate::dialog-close>
                <x-slate::button variant="outline">Cancel</x-slate::button>
            </x-slate::dialog-close>
            <x-slate::button variant="destructive" wire:click="delete">
                Delete
            </x-slate::button>
        </x-slot:footer>
    </x-slate::dialog-content>
</x-slate::dialog>

Best practices

  1. Prefer wire:model / wire:model.live / wire:model.blur on Slate controls — error wiring is automatic.
  2. Put one toaster in the layout; fire slate-toast from components or Alpine.
  3. Don’t nest Alpine x-data roots that fight Livewire morphing on the same node as wire:*.
  4. Use wire:loading on buttons/spinners for submit feedback.
Last updated .