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