Embed Livewire Components Using Wire Extender

Embed Livewire Components Using Wire Extender

Wire Extender allows you to embed any Livewire component on any website or even within a static HTML file.

What if you could embed your Livewire component anywhere? An embedded form, an entire chat widget, you name it! All you need is a way to extend your wire. Luckily, you can get Wire Extender to do the heavy lifting for you.

Try the demo

Create a new HTML file on your local machine with the following contents to get a Livewire powered click counter 😎

1<html>
2<head>
3 <script src="https://unpkg.com/@wire-elements/wire-extender" data-uri="https://wire-elements.dev"></script>
4 </head>
5<body>
6 <livewire data-component="counter" data-params='{"count":10}'></livewire>
7</body>
8</html>

Installation

Please be aware that Wire Extender is in development - Pull requests and feedback are welcome 😄 https://github.com/wire-elements/wire-extender

To get started, require the package via Composer:

1composer require wire-elements/wire-extender

Laravel 10

Next, open app/Http/Middleware/VerifyCsrfToken.php and add the IgnoreForWireExtender trait:

1<?php
2 
3namespace App\Http\Middleware;
4 
5use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
6use WireElements\WireExtender\Http\Middlewares\IgnoreForWireExtender;
7 
8class VerifyCsrfToken extends Middleware
9{
10 use IgnoreForWireExtender;
11 
12 //...
13}

Laravel 11

Create a new middleware app/Http/Middleware/VerifyCsrfToken.php and add the IgnoreForWireExtender trait:

1<?php
2 
3namespace App\Http\Middleware;
4 
5use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as FrameworkClass;
6use WireElements\WireExtender\Http\Middlewares\IgnoreForWireExtender;
7 
8class VerifyCsrfToken extends FrameworkClass
9{
10 use IgnoreForWireExtender;
11}

Next, replace the default middleware:

1<?php
2 
3use App\Http\Middleware\VerifyCsrfToken as CustomVerifyCsrfToken;
4use Illuminate\Foundation\Application;
5use Illuminate\Foundation\Configuration\Exceptions;
6use Illuminate\Foundation\Configuration\Middleware;
7use Illuminate\Foundation\Http\Middleware\ValidateCsrfToken;
8 
9return Application::configure(basePath: dirname(__DIR__))
10 ->withRouting(
11 web: __DIR__.'/../routes/web.php',
12 commands: __DIR__.'/../routes/console.php',
13 health: '/up',
14 )
15 ->withMiddleware(function (Middleware $middleware) {
16 $middleware->web(replace: [
17 ValidateCsrfToken::class => CustomVerifyCsrfToken::class,
18 ]);
19 })
20 ->withExceptions(function (Exceptions $exceptions) {
21 //
22 })->create();

This trait will disable the CSRF token verification for any embeddable component when the wire-extender client makes a request to the /livewire/update endpoint. Why? Because any embeddable component is stateless by default and doesn't support session, and therefore CSRF validation will not work. If you want to support browser sessions, see the next section.

Finally, we need to adjust our CORS settings to allow cross-origin requests. Open config/cors.php and add livewire/* to the paths array. If you are using Laravel 11, you can publish this config file using the publish command (php artisan config:publish cors).

1<?php
2 
3return [
4 'paths' => ['livewire/*'],
5 
6 // ...
7];

Enable browser session support

To enable session support a couple of changes are required. First, you will need to update you cors.php config:

1'paths' => ['livewire/*'],
2'allowed_methods' => ['POST'],
3'allowed_origins' => ['https://targetdomain.test'], // List of sites that will be allowed
4'supports_credentials' => true,

Next, update you .env:

1SESSION_SECURE_COOKIE=true # Add the cookie "Secure" property
2SESSION_HTTP_ONLY=false # Allows to access the cookie via JS
3SESSION_SAME_SITE=none # Sets the cookie "SameSite" property to "none"

Finally, you will need to enable the web middleware by publishing the config file:

1php artisan vendor:publish --tag=wire-extender

Open and edit config/wire-extender.php to enable the web middleware:

1<?php
2 
3return [
4 /*
5 * Define middlewares for the `livewire/embed` route.
6 * Add the 'web' middleware if you want to support sessions.
7 */
8 'middlewares' => [
9 'web',
10 ],
11];

Creating an embeddable component

You can embed any Livewire component, just add the #[Embeddable] attribute to your component class:

1<?php
2 
3namespace App\Livewire;
4 
5use Livewire\Component;
6use WireElements\WireExtender\Attributes\Embeddable;
7 
8#[Embeddable]
9class Counter extends Component
10{
11 public $count = 0;
12 
13 public function increment()
14 {
15 $this->count++;
16 }
17 
18 public function decrement()
19 {
20 $this->count--;
21 }
22 
23 public function render()
24 {
25 return view('livewire.counter');
26 }
27}
1<div>
2 Count: {{ $count }}
3 
4 <button wire:click="increment">+</button>
5 <button wire:click="decrement">-</button>
6</div>

What about component assets and scripts?

They work out of the box, just use the @assets and @script directives as per Livewire's documentation.

1 
2<div>
3 Count: {{ $count }}
4 
5 <button wire:click="increment">+</button>
6 <button wire:click="decrement">-</button>
7</div>
8 
9@assets
10<script src="https://cdn.jsdelivr.net/npm/pikaday/pikaday.js" defer></script>
11<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/pikaday/css/pikaday.css">
12@endassets
13 
14@script
15<script>
16 new Pikaday({ field: $wire.$el.querySelector('[data-picker]') });
17</script>
18@endscript

If you are using nested components, please make sure all components have the #[Embeddable] trait.

Embedding a component

You are almost ready to embed your component. First, let's make sure we publish the wire-extender.js library by running the vendor:publish artisan command.

1php artisan vendor:publish --tag=wire-extender

Now that the asset is published you can include it on the website where you want to embed your Livewire component:

1<html>
2 <head>
3 <script src="//your-domain.com/vendor/wire-elements/wire-extender.js"></script>
4 </head>
5</html>

By default, it will automatically use the domain hosting the script to load the livewire.js library and to make API calls. If you want, you can override these using data attributes:

1<!-- Set custom `livewire.js` url -->
2<script src="/wire-extender.js" data-livewire-asset-uri="//example.com/livewire.js"></script>
3 
4<!-- Set custom `livewire/update` url -->
5<script src="/wire-extender.js" data-update-uri="//example.com/livewire/update"></script>
6 
7<!-- Set custom `livewire/embed` url -->
8<script src="/wire-extender.js" data-embed-uri="//example.com/livewire/embed"></script>

Please be aware that Livewire either uses livewire.js or livewire.min.js depending on your APP_DEBUG setting. Wire extender will always attempt to load livewire/livewire.min.js. If APP_DEBUG is set to true, you will need to use the data-livewire-asset-uri attribute to override the asset url to livewire/livewire.js

You can also use a CDN if you don't want to publish and host the assets on your own website:

1<script src="//unpkg.com/@wire-elements/wire-extender" data-uri="https://example.com"></script>

All that remains is defining the component(s) you want to embed:

1<livewire data-component="counter" data-params='{"count":10}'>
2 <!-- Placeholder... -->
3</livewire>

While the initial API call is made, you can render a custom placeholder. Typically this only takes a few miliseconds. If you have components that take more time to render, consider using the #[Lazy] attribute provided by Livewire and a public function placeholder() method.

That's it! Your component should now appear 🎉

To navigate
Press Enter to select