jonassiewertsen/statamic-livewire
A Statamic addon that integrates Laravel Livewire, letting you build dynamic, reactive components directly inside your Antlers templates and control panel while keeping your familiar Statamic workflow.
composer.json constraints against your Statamic, Laravel, PHP, and Livewire versions. Pin an exact version (e.g. 3.8.1) in composer.json and commit the lock file.composer require jonassiewertsen/statamic-livewire
Statamic addons are auto-discovered; no manual provider registration should be needed.{{# in <head> #}}
{{ livewire:styles }}
{{# before </body> #}}
{{ livewire:scripts }}
If you are on Livewire 3, confirm whether automatic asset injection is active. Double-loading Alpine is a common failure mode.php artisan make:livewire Counter
Edit resources/views/livewire/counter.blade.php, then embed it in any Antlers template:
{{ livewire:counter }}
vendor/jonassiewertsen/statamic-livewire/src. It is small and is the source of truth for supported parameters and component-name parsing. Also run php artisan livewire:list (Livewire 3) to confirm registered component aliases.Pass parameters with Antlers semantics. Use : for evaluated values and plain attributes for literal strings:
{{ livewire:product-filter :category="category" :limit="12" heading="Products" }}
In the component:
public function mount($category = null, $limit = 10, $heading = '')
{
//
}
Test booleans, arrays, and nulls explicitly; Antlers casting can surprise you. For complex configuration, pass a JSON string or an ID and resolve it in mount().
Pass IDs, not Statamic models. Prefer:
{{ livewire:product-card :entry-id="id" }}
Then in the component:
public function mount($entryId)
{
$this->entry = Entry::findOrFail($entryId);
}
Avoid serializing Entry or Term objects into Livewire public properties; snapshots get heavy and stale.
Use Livewire for forms, Statamic for the page shell. Embed {{ livewire:contact-form }} in templates/contact.antlers.html, and keep validation, submission, flash messages, and redirects inside the component's Blade view and class. This keeps the Antlers template clean and testable.
Search and filtering. Let Statamic provide the initial page and collection context; let Livewire handle query state with wire:model.live or wire:model.blur. For large datasets, query and paginate inside the component rather than passing an entire collection into the snapshot.
Loops need stable identity. When rendering a component per entry, give each instance a stable key. If the addon exposes a key parameter, use it:
{{ collection:products }}
{{ livewire:add-to-cart :entry-id="id" :key="id" }}
{{ /collection:products }}
Otherwise set wire:key on the component root or wrap each instance. Test filtering and reordering, where duplicate keys cause state bleed.
Nest Livewire components with Blade, not Antlers. Inside a Livewire view, use normal @livewire(...). The Antlers tag is only for embedding the outer component in a Statamic page.
Asset placement in layouts and partials. Put {{ livewire:styles }} and {{ livewire:scripts }} in the Antlers layout, not in every partial. If some routes use Blade layouts, use @livewireStyles / @livewireScripts there instead and avoid loading both sets.
Testing. Use Livewire::test(ProductFilter::class) for component behavior. For integration, hit the Statamic URL in a feature test and assert the component was rendered, e.g. assertSeeLivewire(ProductFilter::class). That catches tag wiring and asset-injection regressions.
Extension point. If you need custom parameter handling, slot support, or a different tag syntax, copy the addon's small tag class into your own addon. Forking remains an option if a future Statamic or Livewire major lands without a matching addon release.
Maintenance is intermittent, so pin and test. A patch release exists again, but the cadence is irregular and the dependent count is still low, meaning few public examples and bug reports to rely on. Pin an exact version, test Statamic/Livewire upgrades in a branch, and keep a fork or replacement plan in your back pocket.
Upgrade to 3.8.1 if you build entries from dates. v3.8.1 fixes a bug where a date could not be parsed by Entry::make() (PR #73). This bites components that accept a date string from Antlers and rehydrate or construct an entry from it. If you have patterns like:
{{ livewire:events-list :from="date" :to="date" }}
and the component passes that value into Entry::make(), you were likely hitting a silent failure or exception. Pin 3.8.1 or later, and still normalize the string yourself rather than relying on implicit casting:
public function mount(string $from)
{
$this->from = Carbon::parse($from);
}
Double-loaded Alpine. Livewire 3 bundles Alpine. If you also include {{ livewire:scripts }} while automatic injection is enabled, you can get "Alpine is already loaded" warnings or broken directives. Either disable Livewire's automatic injection via config/livewire.php ('inject_assets' => false) or remove the manual tags. Verify only one Alpine instance exists in the browser console.
Static caching can leak or freeze component state. Statamic's static cache may serve the same Livewire snapshot HTML to every visitor. That is fine for public initial state but dangerous if the component renders user-specific data. Exclude personalized pages from static caching, or make the component load user-specific data after hydration. Livewire's POST updates are not cached, but the initial HTML is.
Antlers parameter casting. :foo="bar" evaluates bar as an Antlers variable; foo="bar" passes the literal string "bar". Arrays and objects can be passed but may be cast unexpectedly. Test edge cases and prefer IDs or JSON for complex data. Date and number values in particular should be validated and normalized in mount(), not trusted as-is.
Component name parsing. Antlers tag syntax and Livewire's dot/slash namespaces do not always line up. If {{ livewire:forms.contact }} fails to resolve, register a simpler alias such as contact-form, or check the tag class to see how the method name is interpreted.
Keep Livewire directives in Blade. Do not scatter wire:model, wire:click, or wire:submit through Antlers markup. Put them in the component's Blade view. Mixing Antlers and Livewire markup makes escaping, debugging, and conditional rendering harder.
Live Preview and SPA navigation. Statamic's Live Preview and Livewire's wire:navigate can conflict, resetting component state or double-handling navigation. Test the editor workflow before relying on wire:navigate for Statamic routes.
Debugging checklist:
/livewire/update: check php artisan route:list | grep livewire and ensure the page uses the web middleware group.php artisan livewire:list, and check auto-discovery or Livewire::component() registration.Entry::make() — then log the raw parameter type arriving in mount().Performance and security. Every interaction is a request. Avoid embedding dozens of components per page; use Livewire lazy loading or wire:init for heavy widgets. Treat public properties as untrusted input—they are serialized into the HTML snapshot and can be tampered with. Authorize actions and never store secrets in public properties.
How can I help you explore Laravel packages today?