PHPackages                             mwguerra/wire-bridge - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. mwguerra/wire-bridge

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

mwguerra/wire-bridge
====================

Seamless two-way reactive bridge between Livewire 4 and Vue 3 / React components with automatic state persistence.

v1.0.0(1mo ago)11—0%MITPHPPHP ^8.3

Since Mar 21Pushed 1mo agoCompare

[ Source](https://github.com/mwguerra/wire-bridge)[ Packagist](https://packagist.org/packages/mwguerra/wire-bridge)[ RSS](/packages/mwguerra-wire-bridge/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (3)Versions (2)Used By (0)

WireBridge
==========

[](#wirebridge)

**Seamless two-way reactive bridge between Livewire 4 and Vue 3 / React.**

State persistence, Filament 5 support, artisan generators, and Vite auto-import included.

**Compatible with:** Laravel 11 / 12 / 13 · Livewire 4 · Filament 5 · PHP 8.3+

---

Philosophy
----------

[](#philosophy)

Modern Laravel applications are built on Livewire. It is powerful, productive, and keeps you in PHP. But sometimes you need a rich interactive component — a chart library, a drag-and-drop board, a complex form widget — and the best implementation exists in Vue or React.

The usual answer is "pick one stack." Either go all-in on Livewire + Alpine, or abandon Livewire for Inertia. WireBridge rejects that tradeoff.

**The core idea:** Livewire owns the page, the routing, the server state, and the lifecycle. Vue or React owns a region of the DOM where rich interactivity lives. The bridge makes Livewire public properties behave like native framework state inside that region — two-way bound, reactive, and persisted — so the JS component feels like it is running in a normal Vue or React application.

You write a normal Vue `` or a normal React function component. The only difference is one import: `useLivewire()` instead of defining your own state. Everything else — child components, third-party libraries, CSS frameworks, local `ref()` or `useState()` — works exactly as it would in a standalone JS app.

The problem it solves
---------------------

[](#the-problem-it-solves)

Without WireBridge, embedding Vue or React inside Livewire means:

- Manually passing data through `@json()` and data attributes, then parsing them in JS.
- Using `wire:ignore` to prevent Livewire from destroying your JS mount, but losing all reactivity between the two worlds.
- Writing custom event listeners to push data from JS back to Livewire and vice versa.
- Losing all JS state on every `wire:navigate`, parent re-render, or page reload.
- Duplicating state management: Livewire properties on the server, a separate store (Pinia, Redux, Zustand) on the client.

WireBridge eliminates all of this. One composable gives you reactive access to every Livewire public property, a way to call any PHP method, and a local state layer that persists across re-mounts — all without writing any glue code.

---

Features
--------

[](#features)

### Two-way reactive data binding

[](#two-way-reactive-data-binding)

Livewire public properties are automatically synced into your Vue or React component. Change a property in Vue and it pushes to Livewire. Change it in PHP and it appears in Vue. No events, no watchers, no manual synchronization.

```

{{ state.count }}
```

```
// React: same thing, immutable convention
 set('count', state.count + 1)}>{state.count}
```

### Call PHP methods from JS

[](#call-php-methods-from-js)

Any public method on your Livewire component is callable from the JS side via `wire`. Return values come back as promises.

```
// Vue or React — identical syntax
wire.addItem('Buy groceries');
wire.save();
wire.deletePost(42).then(() => console.log('deleted'));
```

### JS-only local state with persistence

[](#js-only-local-state-with-persistence)

UI concerns like sidebar toggles, form drafts, scroll positions, and active tabs live in `local`. This state is never sent to PHP but survives page reloads, `wire:navigate`, and parent Livewire re-renders via `sessionStorage`.

```

```

```
// React
 setLocal('draft', e.target.value)} />
```

### Automatic state persistence

[](#automatic-state-persistence)

Both `state` (Livewire properties) and `local` (JS-only) are persisted to `sessionStorage` on every change. When the component re-mounts — after a page reload, `wire:navigate`, or a parent Livewire re-render — the bridge restores the previous state instantly, before the server round-trip completes.

On the PHP side, `#[Session]` keeps Livewire properties in the server session as well, giving you double persistence (client + server).

### Artisan generators

[](#artisan-generators)

One command scaffolds the Livewire class, Blade view, and Vue/React component with `useLivewire()` already wired up.

```
php artisan make:wire-bridge TodoList --vue
php artisan make:wire-bridge Dashboard --react
php artisan make:wire-bridge RevenueChart --vue --filament
```

### Vite auto-import

[](#vite-auto-import)

A Vite plugin scans your components directory and auto-registers everything. Drop a new `.vue` or `.jsx` file into the folder, and it is immediately available in Blade — no manual registration, no touching `app.js`.

### Filament 5 support

[](#filament-5-support)

A `WireBridgeWidget` base class lets you embed Vue or React components inside Filament dashboards, panels, and resource pages with zero Blade files.

### Framework-agnostic core

[](#framework-agnostic-core)

The bridge is three layers: a framework-agnostic core (`core.js`) that talks to `$wire`, and thin adapters for Vue (`vue.js`) and React (`react.js`). You can mix frameworks on the same page — Vue for the sidebar, React for the main panel — because each mount is independent.

---

Installation
------------

[](#installation)

### Step 1: Install the package

[](#step-1-install-the-package)

```
composer require mwguerra/wire-bridge
```

### Step 2: Run the installer

[](#step-2-run-the-installer)

```
php artisan wire-bridge:install --vue      # Vue only
php artisan wire-bridge:install --react    # React only
php artisan wire-bridge:install --both     # Both frameworks
```

This publishes the JS bridge files into `resources/js/livewire-bridge/`, the mount script, example components, and installs the npm dependencies.

Add `--no-deps` to skip the npm install step if you prefer to manage dependencies yourself.

### Step 3: Configure Vite

[](#step-3-configure-vite)

Add the appropriate framework plugins and (optionally) the auto-import plugin to your `vite.config.js`:

```
// vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';                                          // if using Vue
import react from '@vitejs/plugin-react';                                      // if using React
import { wireBridgeAutoImport } from './resources/js/livewire-bridge/vite-plugin'; // optional

export default defineConfig({
    plugins: [
        laravel({
            input: ['resources/css/app.css', 'resources/js/app.js'],
            refresh: true,
        }),
        vue(),                     // if using Vue
        react(),                   // if using React
        wireBridgeAutoImport(),    // optional: auto-discovers components
    ],
    resolve: {
        alias: {
            vue: 'vue/dist/vue.esm-bundler.js',   // if using Vue
        },
    },
});
```

### Step 4: Set up app.js

[](#step-4-set-up-appjs)

**With auto-import (recommended):**

```
// resources/js/app.js
import './bootstrap';
import 'virtual:wire-bridge';   // auto-registers all Vue/React components
```

**Without auto-import (manual registration):**

```
// resources/js/app.js
import './bootstrap';
import { registerComponent } from './livewire-mount';

import ChatApp from './components/ChatApp/ChatApp.vue';
registerComponent('chat-app', { framework: 'vue', component: ChatApp });

import Dashboard from './components/Dashboard/Dashboard';
registerComponent('dashboard', { framework: 'react', component: Dashboard });
```

---

Quick start
-----------

[](#quick-start)

### Generate a component

[](#generate-a-component)

```
php artisan make:wire-bridge TodoList --vue
```

This creates three files:

**`app/Livewire/TodoList.php`** — the Livewire component:

```
