Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Livewire Assistant Laravel Package

pharaonic/livewire-assistant

A Livewire assistant package for Laravel that helps you add an in-app helper or chat-style assistant to your components with minimal setup. Useful for quick integration, though it is a small package with limited adoption, so review the docs and source before relying on it in production.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and wire up the script tag.

composer require pharaonic/livewire-assistant

Confirm your baseline first — the package will not run on a vulnerable Livewire:

composer show livewire/livewire | grep versions   # must be >= 2.12.7

2.12.7 is the first Livewire 2 release carrying the fix for CVE-2024-47823, so treat it as a hard floor, not a suggestion.

Then drop the directive into your layout (head or before </body>):

@livewireAssistantScripts

That tag carries data-turbo-eval="false", which matters if you're on Turbo — see Gotchas.

Where to look first. The official docs are the authority, not the package description. The description text talks about Artisan scaffolding and stubs; the actual shipped API in 2.0.0 is a JavaScript-to-Livewire component bridge (get / set / call). Plan around the bridge.

First use case — the one that justifies the dependency. You have a non-Livewire widget (Flatpickr, Tom Select, a signature pad, a third-party map) that needs to write into a Livewire component's state and then trigger a server action:

const assistant = LivewireAssistant.find('date-picker-card'); // matches wire:id

assistant.set('date', '2024-01-01');
await assistant.call('save');

That's the whole value proposition. If you don't have JS widgets that need to drive Livewire state, you don't need this package — wire:model and $wire cover you.

Implementation Patterns

Mirror wire:model in JS with set / get / call.

The three methods map cleanly onto the Livewire mental model you already have:

Bridge Livewire equivalent
set(path, value) wire:model (immediate)
set(path, value, { live: false }) wire:model.defer
get(path) reading $wire.property
call(method, ...args) invoking a component action

Deferred writes are the pattern you'll reach for most. High-frequency inputs (search boxes, sliders, rich-text editors firing on every keystroke) must not generate a request per event. Batch them:

assistant.set('search', 'foo', { live: false });
assistant.set('perPage', 50, { live: false });
// nothing has hit the server yet
const result = await assistant.call('submit'); // one request, both values

The promise resolves with that request, so you get a natural commit point: fire deferred writes as the user types, and flush with a single call() on submit/blur.

Use call() return values instead of inventing a response channel. This is the feature that turns the bridge from fire-and-forget into a real request/response loop:

const { valid, errors } = await assistant.call('validateStep', 2);
if (!valid) showErrors(errors);

Server-side, just return an array from the Livewire method — no events, no polling, no separate endpoint. Validation-before-submit and lookup flows both become trivial.

Isolate bridge calls in one module per widget. Don't sprinkle LivewireAssistant.find(...) through your JS. Write a thin adapter so the rest of the app doesn't know the package exists:

// resources/js/widgets/date-picker.js
export function bindDatePicker(el, componentId) {
  const assistant = LivewireAssistant.find(componentId);
  const picker = flatpickr(el, {
    onChange: ([date]) => assistant.set('date', date.toISOString(), { live: false }),
    onClose:  () => assistant.call('commitDate'),
  });
  return () => { picker.destroy(); };
}

That single seam is also your migration path when Livewire 3 lands and this package stops fitting — you rewrite one file, not fifty call sites.

Alpine integration. Alpine is already in every Livewire 2 app, so let Alpine own the lifecycle and the assistant own the transport:

<div x-data x-init="
    const a = LivewireAssistant.find(@js($this->getId()));
    $watch('query', v => a.set('query', v, { live: false }));
">

Keep Alpine state as the source of truth for UI, push to the component on boundaries (blur, debounce, submit) rather than on every tick.

Turbo/Turbolinks. The package hooks Livewire's livewire-turbolinks adapter and listens for navigation events itself. Your job is only to make sure the script tag renders on every page — don't hand-roll re-initialization on turbo:load.

Gotchas and Tips

Livewire 3 is not supported, and won't be retrofitted. 2.0.0 is purpose-built for Livewire 2 using Livewire 2's documented hooks. Livewire 3 reworked the front-end contract entirely. Before you adopt, confirm Livewire 3 isn't on your roadmap — if it is, this is a time-boxed stopgap, not a foundation.

The support matrix stops at Laravel 10 / PHP 8.3. Laravel 7.30 (PHP 8.0), 8.75 (PHP 8.0–8.1), 9 (PHP 8.0–8.2), 10 (PHP 8.1–8.3). Laravel 11/12 and PHP 8.4 are not stated as supported. Run a compatibility spike on a branch before committing; composer resolving is not the same as the adapter working.

Deferred reads go stale by design. get(path) returns the locally deferred value until the next request resolves — that's the point, but it means the bridge and server-rendered state can diverge inside that window:

assistant.set('total', 999, { live: false });
console.log(assistant.get('total')); // 999 — server knows nothing yet

Any optimistic UI layered on top must tolerate a rollback when the server disagrees. If you need truth, force a round-trip with call().

unsupported-operation is gone in 2.x. Livewire 2 performs every bridge operation, so the error is unreachable. Audit before upgrading: any defensive catch branch or test asserting on that code is now dead code that will either pass for the wrong reason or fail confusingly. Delete it deliberately rather than discovering it in production.

component-not-found means a lifecycle race, not a bug. Calling find() before the component is mounted is the #1 failure mode. Guard it:

const a = LivewireAssistant.find(id);
if (!a) return; // retry after livewire:load / next tick

The ID you pass must match the rendered wire:id attribute exactly — including on nested or repeated components, where IDs are generated and not stable across renders. Read it from the DOM (el.closest('[wire\\:id]')) rather than hardcoding.

Don't re-initialize on turbo:load. data-turbo-eval="false" suppresses script re-execution on navigation; the package registers its own Turbo listeners. Manual re-init will double-bind and produce duplicate call()s — the classic "my action fires three times" bug.

Debugging. Everything is on the JS side, so stay in the console: inspect the assistant instance, check find() returned non-null, confirm the component is mounted, and watch the Network tab to verify deferred writes actually coalesce into one request rather than one per set.

Vendor risk is real and should be priced in. One star, zero dependents, single-vendor maintenance, and an upstream hook surface (Livewire 2's) that is frozen — no upstream fixes should be expected. Mitigate with the adapter-module pattern above, keep the dependency confined to resources/js/widgets/, and don't let it leak into Blade partials or your form components.

Extension points worth knowing. The integration API, component bridge, attributes, and error codes are unchanged from 1.x, so 1.x guidance still applies to configurability. Check the docs for attribute overrides and custom error handlers before forking anything — the bridge is designed to be wrapped, and wrapping beats forking for a package you'll eventually need to drop.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core