Skip to content

Laravel

Blade renders the page. Brio owns only a marked widget. No Brio Vite plugin is needed; Laravel’s existing asset pipeline is enough. Start with the shared lifecycle helper.

@php($count = 3)
<section data-brio-counter data-start="{{ $count }}" aria-label="Counter">
<p>Count: <output b-text="$data.count" aria-live="polite">{{ $count }}</output></p>
<button type="button" b-on-click="$data.count++">Add one</button>
</section>

Blade escapes the server value. Brio’s $data syntax does not use Blade’s double braces. Keep expressions developer-authored; never insert raw user input into directive attributes.

Install @jnreis/briojs with your app’s package manager and copy widgets.js to resources/js/brio-widgets.js. Add this to resources/js/app.js:

import { createApp } from '@jnreis/briojs';
import { createWidgetManager } from './brio-widgets.js';
const widgets = createWidgetManager(createApp);
const mount = () => widgets.mountWithin(document);
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', mount, { once: true });
} else {
mount();
}
if (import.meta.hot) {
import.meta.hot.dispose(() => widgets.disposeWithin(document));
}

Load it once in your Blade layout using the application’s existing @vite('resources/js/app.js') setup. The HMR cleanup disposes the previous entrypoint’s widgets before its replacement mounts them.

Do not let Livewire and Brio morph the same subtree. Put wire:ignore on the Brio root if the widget’s contents belong entirely to Brio. That attribute does not prevent the whole root from being removed by an ancestor update: dispose it before such a removal and mount newly inserted roots afterward.

For Livewire Navigate, register these listeners once in the app entrypoint above, not in each page fragment:

document.addEventListener('livewire:navigating', () => {
widgets.disposeWithin(document);
});
document.addEventListener('livewire:navigated', mount);

These navigation hooks do not cover every Livewire component morph. Use the appropriate pre-removal hooks for your installed Livewire version, or keep Brio outside Livewire-managed regions. wire:ignore is an ownership boundary, not a universal lifecycle integration.

Use normal Blade forms with @csrf, Laravel authorization, validation, and rendered errors. The sample counter is local UI state only. For richer server data use Laravel’s JSON serialization helpers, not unescaped JavaScript interpolation. Without a bundler, follow the self-hosted browser bundle setup.