Livewire Development
When to Apply
Activate this skill when:
- Creating or modifying Livewire components
- Using wire: directives (model, click, loading, sort, intersect)
- Implementing islands or async actions
- Writing Livewire component tests
Documentation
Use search-docs for detailed Livewire 4 patterns and documentation.
Basic Usage
Creating Components
Single-file component (default in v4)
{{ $assist->artisanCommand('make:livewire create-post') }}
Multi-file component
{{ $assist->artisanCommand('make:livewire create-post --mfc') }}
Class-based component (v3 style)
{{ $assist->artisanCommand('make:livewire create-post --class') }}
With namespace
{{ $assist->artisanCommand('make:livewire Posts/CreatePost') }}
Converting Between Formats
Use php artisan livewire:convert create-post to convert between single-file, multi-file, and class-based formats.
Component Format Reference
| Format |
Flag |
Structure |
| Single-file (SFC) |
default |
PHP + Blade in one file |
| Multi-file (MFC) |
--mfc |
Separate PHP class, Blade, JS, tests |
| Class-based |
--class |
Traditional v3 style class |
| View-based |
⚡ prefix |
Blade-only with functional state |
Single-File Component Example
Livewire 4 Specifics
Key Changes From Livewire 3
These things changed in Livewire 4, but may not have been updated in this application. Verify this application's setup to ensure you follow existing conventions.
- Use
Route::livewire() for full-page components; config keys renamed: layout → component_layout, lazy_placeholder → component_placeholder.
wire:model now ignores child events by default (use wire:model.deep for old behavior); wire:scroll renamed to wire:navigate:scroll.
- Component tags must be properly closed;
wire:transition now uses View Transitions API (modifiers removed).
- JavaScript:
$wire.$js('name', fn) → $wire.$js.name = fn; commit/request hooks → interceptMessage()/interceptRequest().
New Features
- Component formats: single-file (SFC), multi-file (MFC), view-based components.
- Islands (
@island) for isolated updates; async actions (wire:click.async, #[Async]) for parallel execution.
- Deferred/bundled loading:
defer, lazy.bundle for optimized component loading.
| Feature |
Usage |
Purpose |
| Islands |
@island(name: 'stats') |
Isolated update regions |
| Async |
wire:click.async or #[Async] |
Non-blocking actions |
| Deferred |
defer attribute |
Load after page render |
| Bundled |
lazy.bundle |
Load multiple together |
New Directives
wire:sort, wire:intersect, wire:ref, .renderless, .preserve-scroll are available for use.
data-loading attribute automatically added to elements triggering network requests.
| Directive |
Purpose |
wire:sort |
Drag-and-drop sorting |
wire:intersect |
Viewport intersection detection |
wire:ref |
Element references for JS |
.renderless |
Component without rendering |
.preserve-scroll |
Preserve scroll position |
Best Practices
- Always use
wire:key in loops
- Use
wire:loading for loading states
- Use
wire:model.live for instant updates (default is debounced)
- Validate and authorize in actions (treat like HTTP requests)
Configuration
smart_wire_keys defaults to true; new configs: component_locations, component_namespaces, make_command, csp_safe.
Alpine & JavaScript
wire:transition uses browser View Transitions API; $errors and $intercept magic properties available.
- Non-blocking
wire:poll and parallel wire:model.live updates improve performance.
For interceptors and hooks, see reference/javascript-hooks.md.
Testing
Livewire::test(Counter::class)
->assertSet('count', 0)
->call('increment')
->assertSet('count', 1);
Verification
- Browser console: Check for JS errors
- Network tab: Verify Livewire requests return 200
- Ensure
wire:key on all @foreach loops
Common Pitfalls
- Missing
wire:key in loops → unexpected re-rendering
- Expecting
wire:model real-time → use wire:model.live
- Unclosed component tags → syntax errors in v4
- Using deprecated config keys or JS hooks
- Including Alpine.js separately (already bundled in Livewire 4)
1---2name: livewire-development3description: Develops reactive Livewire 4 components. Activates when creating, updating, or modifying Livewire components; working with wire:model, wire:click, wire:loading, or any wire: directives; adding real-time updates, loading states, or reactivity; debugging component behavior; writing Livewire tests; or when the user mentions Livewire, component, counter, or reactive UI.4---5
6# Livewire Development
7
8## When to Apply
9
10Activate this skill when:
11
12- Creating or modifying Livewire components
13- Using wire: directives (model, click, loading, sort, intersect)
14- Implementing islands or async actions
15- Writing Livewire component tests
16
17## Documentation
18
19Use `search-docs` for detailed Livewire 4 patterns and documentation.
20
21## Basic Usage
22
23### Creating Components
24
25<code-snippet name="Component Creation Commands" lang="bash">
26
27# Single-file component (default in v4)
28
29{{ $assist->artisanCommand('make:livewire create-post') }}
30
31# Multi-file component
32
33{{ $assist->artisanCommand('make:livewire create-post --mfc') }}
34
35# Class-based component (v3 style)
36
37{{ $assist->artisanCommand('make:livewire create-post --class') }}
38
39# With namespace
40
41{{ $assist->artisanCommand('make:livewire Posts/CreatePost') }}
42
43</code-snippet>
44
45### Converting Between Formats
46
47Use `php artisan livewire:convert create-post` to convert between single-file, multi-file, and class-based formats.
48
49### Component Format Reference
50
51| Format | Flag | Structure |
52|--------|------|-----------|
53| Single-file (SFC) | default | PHP + Blade in one file |
54| Multi-file (MFC) | `--mfc` | Separate PHP class, Blade, JS, tests |
55| Class-based | `--class` | Traditional v3 style class |
56| View-based | ⚡ prefix | Blade-only with functional state |
57
58### Single-File Component Example
59
60<code-snippet name="Single-File Component Example" lang="php">
61
62<?php
63use Livewire\Component;
64
65new class extends Component {
66 public int $count = 0;
67
68 public function increment(): void
69 {
70 $this->count++;
71 }
72}
73?>
74
75<div>
76 <button wire:click="increment">Count: @{{ $count }}</button>
77</div>
78
79</code-snippet>
80
81## Livewire 4 Specifics
82
83### Key Changes From Livewire 3
84
85These things changed in Livewire 4, but may not have been updated in this application. Verify this application's setup to ensure you follow existing conventions.
86
87- Use `Route::livewire()` for full-page components; config keys renamed: `layout` → `component_layout`, `lazy_placeholder` → `component_placeholder`.
88- `wire:model` now ignores child events by default (use `wire:model.deep` for old behavior); `wire:scroll` renamed to `wire:navigate:scroll`.
89- Component tags must be properly closed; `wire:transition` now uses View Transitions API (modifiers removed).
90- JavaScript: `$wire.$js('name', fn)` → `$wire.$js.name = fn`; `commit`/`request` hooks → `interceptMessage()`/`interceptRequest()`.
91
92### New Features
93
94- Component formats: single-file (SFC), multi-file (MFC), view-based components.
95- Islands (`@island`) for isolated updates; async actions (`wire:click.async`, `#[Async]`) for parallel execution.
96- Deferred/bundled loading: `defer`, `lazy.bundle` for optimized component loading.
97
98| Feature | Usage | Purpose |
99|---------|-------|---------|
100| Islands | `@island(name: 'stats')` | Isolated update regions |
101| Async | `wire:click.async` or `#[Async]` | Non-blocking actions |
102| Deferred | `defer` attribute | Load after page render |
103| Bundled | `lazy.bundle` | Load multiple together |
104
105### New Directives
106
107- `wire:sort`, `wire:intersect`, `wire:ref`, `.renderless`, `.preserve-scroll` are available for use.
108- `data-loading` attribute automatically added to elements triggering network requests.
109
110| Directive | Purpose |
111|-----------|---------|
112| `wire:sort` | Drag-and-drop sorting |
113| `wire:intersect` | Viewport intersection detection |
114| `wire:ref` | Element references for JS |
115| `.renderless` | Component without rendering |
116| `.preserve-scroll` | Preserve scroll position |
117
118## Best Practices
119
120- Always use `wire:key` in loops
121- Use `wire:loading` for loading states
122- Use `wire:model.live` for instant updates (default is debounced)
123- Validate and authorize in actions (treat like HTTP requests)
124
125## Configuration
126
127- `smart_wire_keys` defaults to `true`; new configs: `component_locations`, `component_namespaces`, `make_command`, `csp_safe`.
128
129## Alpine & JavaScript
130
131- `wire:transition` uses browser View Transitions API; `$errors` and `$intercept` magic properties available.
132- Non-blocking `wire:poll` and parallel `wire:model.live` updates improve performance.
133
134For interceptors and hooks, see [reference/javascript-hooks.md](reference/javascript-hooks.md).
135
136## Testing
137
138<code-snippet name="Testing Example" lang="php">
139
140Livewire::test(Counter::class)
141 ->assertSet('count', 0)
142 ->call('increment')
143 ->assertSet('count', 1);
144
145</code-snippet>
146
147## Verification
148
1491. Browser console: Check for JS errors
1502. Network tab: Verify Livewire requests return 200
1513. Ensure `wire:key` on all `@foreach` loops
152
153## Common Pitfalls
154
155- Missing `wire:key` in loops → unexpected re-rendering
156- Expecting `wire:model` real-time → use `wire:model.live`
157- Unclosed component tags → syntax errors in v4
158- Using deprecated config keys or JS hooks
159- Including Alpine.js separately (already bundled in Livewire 4)