Modal Component

Learn everything there is to know about the Modal Component.

Wire Elements - Modal Pro

Install the modal base component

To use the modal component, you must add the modal base component @livewire('modal-pro') to every page of your application where you want to be able to use the modal—for example, resources/views/layouts/app.blade.php

1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1">
6 
7 <title>Laravel</title>
8 <script src="//unpkg.com/alpinejs" defer></script>
9 
10 @livewireStyles
11</head>
12<body>
13 
14 <!-- Require the Modal Pro component -->
15 @livewire('modal-pro')
16 
17 @livewireScripts
18</body>
19</html>

Add the @livewire('modal-pro') directive to your layout.

Compile Javascript

This component requires some additional Javascript so ensure this is compiled by requiring the script in your resources/js/bootstrap.js:

1require('../../vendor/wire-elements/pro/resources/js/overlay-component.js')

To compile you will also need to install the following NPM dependencies:

  • npm i @alpinejs/focus

Make sure you enable the Alpine focus plugin in your resources/js/app.js:

1require('./bootstrap');
2import Alpine from 'alpinejs';
3import focus from '@alpinejs/focus'
4Alpine.plugin(focus)
5window.Alpine = Alpine;
6Alpine.start();

It’s also possible to include the required resources directly; see the following next step.

Include Javascript and CSS directly

You can include Javascript and CSS (Bootstrap only) directly by publishing the package assets. If you are using the Boostrap preset, you must include the additional CSS.

1php artisan vendor:publish --tag=wire-elements-pro-assets
2 
3Copied Directory [/wire-elements-pro/resources/dist] To [/public/vendor/wire-elements-pro]
4Publishing complete.

Publish package assets.

1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1">
6 
7 <title>Laravel</title>
8 <script src="//unpkg.com/alpinejs" defer></script>
9 
10 <!-- Include the overlay-component.css stylesheet -->
11 <link rel="stylesheet" href="{{ asset('vendor/wire-elements-pro/css/bootstrap-overlay-component.css') }}">
12 
13 @livewireStyles
14</head>
15<body>
16 
17 <!-- //.... -->
18 
19 <!-- Include the overlay-component.js script -->
20 <script src="{{ asset('vendor/wire-elements-pro/js/overlay-component.js') }}"></script>
21</body>
22</html>

Make sure to republish assets when you update the package.

Tailwind CSS configuration

If you use Tailwind as your CSS framework, it’s essential to include the Wire Element components in the contents array. Add the following paths to the content array to ensure the required CSS is generated.

1module.exports = {
2 
3 content: [
4 './vendor/wire-elements/pro/config/wire-elements-pro.php',
5 './vendor/wire-elements/pro/**/*.blade.php',
6 ],
7 
8 //....
9};

Configure the tailwind.config.js content array

Chances are you want to make changes to the look and feel of the modal. Publishing the views is one possibility, but staying up to date with any changes will be more time-consuming. For that reason, the Tailwind CSS is in a separate file, so you can make adjustments without the need to edit the blade file. Even if you don't want to make any changes, you must include the CSS like this:

1@tailwind base;
2@tailwind components;
3@tailwind utilities;
4 
5@layer components {
6 @import "../../vendor/wire-elements/pro/resources/css/tailwind/overlay-component.css";
7 
8 // Add your customizations here
9 
10 // Example: Disable the transition animation when reduced motion is enabled
11 .wep-modal-content,
12 .wep-slide-over-container-inner-wrap {
13 @apply motion-reduce:transition-none;
14 }
15}

Add the import statement to your resources/css/app.css

Configuration

If you want to make any configuration changes to the modal component, you will need to publish the config file using the following command:

1php artisan vendor:publish --tag=wire-elements-pro-config
2 
3Copied File [/wire-elements-pro/config/wire-elements-pro.php] To [/config/wire-elements-pro.php]
4Publishing complete.

Publish the Wire Elements Pro configuration file

The config file contains the default modal behavior and attributes. The different behaviors and attributes are explained further along in this document.

Using Bootstrap as your front-end framework

If you are using Bootstrap as your front-end framework, you will have to change the preset from Tailwind to Bootstrap:

1return [
2 'default' => 'bootstrap',
3 
4 // ...
5];

Creating your first modal

You create a Livewire component as you would regularly do to get started. For example, by running the make command:

1php artisan livewire:make UsersOverview
2 
3COMPONENT CREATED 🤙
4 
5CLASS: app/Http/Livewire/UsersOverview.php
6VIEW: resources/views/livewire/users-overview.blade.php

Next, you will need to extend your component with the Modal class instead of the Component class.

1namespace App\Http\Livewire;
2 
3use Livewire\Component; // Remove
4use WireElements\Pro\Components\Modal\Modal;
5 
6class UsersOverview extends Modal
7{
8 public function render()
9 {
10 return view('livewire.users-overview');
11 }
12}

Extend the Modal class instead of the default Livewire component class.

The modal will show the contents of your view. There is no structure applied by default, so you are free to add anything you like. Alternatively, you can use our Blade component:

1<x-wire-elements-pro::tailwind.modal on-submit="save" :content-padding="false">
2 <x-slot name="title">Your Title</x-slot>
3 
4 <!-- No padding will be applied because the component attribute "content-padding" is set to false -->
5 <div>
6 <label>Your email</label>
7 <input type="email" placeholder="[email protected]">
8 </div>
9 
10 <x-slot name="buttons">
11 <button type="submit">
12 Save Changes
13 </button>
14 <button type="button" wire:click="$emit('modal.close')">
15 Cancel
16 </button>
17 </x-slot>
18</x-wire-elements-pro::tailwind.modal>

To get started, wrap your content using the blade component x-wire-elements-pro::tailwind.modal. If you use Boostrap, you need to use x-wire-elements-pro::bootstrap.modal.

This component accepts a few arguments to make things easier. For example, you can use the on-submit attribute to define the method to be called on your Livewire component when the form is submitted.

By default, padding will be applied to the body of the modal. In some cases, you might not want this, for example, when adding a full-width table to your modal. If this is the case, you can add :content-padding="false". To set the title for your modal you must use the title slot.

If you want to display buttons on your modal you can add these to the buttons slot.

Setting behavior and attributes

If you want to change the behavior or attributes for a specific modal, you can create the following static methods on your component class.

1namespace App\Http\Livewire;
2 
3use WireElements\Pro\Components\Modal\Modal;
4 
5class UsersOverview extends Modal
6{
7 public function render()
8 {
9 return view('livewire.users-overview');
10 }
11 
12 public static function behavior(): array
13 {
14 return [];
15 }
16 
17 public static function attributes(): array
18 {
19 return [];
20 }
21}

The behavior and attributes you define on a modal will override the defaults specified in the wire-elements-pro.php config file. Let’s take a look at the available options.

1namespace App\Http\Livewire;
2 
3use WireElements\Pro\Components\Modal\Modal;
4 
5class UsersOverview extends Modal
6{
7 public function render()
8 {
9 return view('livewire.users-overview');
10 }
11 
12 public static function behavior(): array
13 {
14 return [
15 // Close the modal if the escape key is pressed
16 'close-on-escape' => true,
17 // Close the modal if someone clicks outside the modal
18 'close-on-backdrop-click' => true,
19 // Trap the users focus inside the modal (e.g. input autofocus and going back and forth between input fields)
20 'trap-focus' => true,
21 // Remove all unsaved changes once someone closes the modal
22 'remove-state-on-close' => false,
23 ];
24 }
25 
26 public static function attributes(): array
27 {
28 return [
29 // Set the modal size to 2xl, you can choose between:
30 // xs, sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl, 6xl, 7xl
31 'size' => '2xl',
32 ];
33 }
34}
Context Method
Javascript
1Livewire.emit('modal.open', 'users-overview');
Blade
1<button onclick="Livewire.emit('modal.open', 'users-overview')">
2Open</button>
Inside a Livewire Component View
1<button wire:click="$emit('modal.open', 'show-users')">Open</button>
Inside a Livewire Component Class
1$this->emit('modal.open', 'users-overview');

Passing properties

Often you want to pass properties to your modal, for example, when you want to open a modal to edit a user. You can do this by adding a third argument to the examples listed in the table above.

1class EditUser extends Modal
2{
3 public int|User $user;
4 
5 public function mount(User $user) {
6 $this->user = $user;
7 }
8 
9 public function render()
10 {
11 return view('livewire.edit-user');
12 }
13}

To open this component you would use one of the following ways:

Context Method
Javascript
1Livewire.emit('modal.open', 'edit-user', {'user': 1});
Blade
1<button onclick="Livewire.emit('modal.open', 'edit-user', {'user': 1})">Open</button>
Inside a Livewire Component View
1<button wire:click="$emit('modal.open', 'edit-user', {'user': 1})">Open</button>
Inside a Livewire Component Class
1$this->emit('modal.open', 'edit-user', ['user' => 1]);

Passing modal behavior and attributes

It’s also possible to override the modal behavior and attributes when opening a modal by passing a fourth and fifth argument:

1Livewire.emit('modal.open', 'edit-user', {"user": 1}, {"size":"2xl"}, {"close-on-escape": false});

Closing your modal

To close your modal you can use a similar syntax as opening a modal.

Context Method
Javascript
1Livewire.emit('modal.close');
Blade
1<button onclick="Livewire.emit('modal.close')">Close</button>
Inside a Livewire Component View
1<button wire:click="$emit('modal.close')">Close</button>
Inside a Livewire Component Class
1$this->close();

By default, when you close a child modal (a child modal means you’ve opened a second modal from an existing modal), it will return to the parent modal. Think of this as your browser history; when you close a modal, you are doing the same as going back to the previous page. In some cases, you might not want this behavior. You can pass the force argument to force the closing of all modals.

1Livewire.emit('modal.close', { force: true });

If you don’t want to force all modals to be closed, but instead, you want to remove one or more modals from the history, you can use the andForget parameter.

1class DeleteUser extends Modal
2{
3 public int|User $user;
4 
5 public function mount(User $user) {
6 $this->user = $user;
7 }
8 
9 public function confirmDelete()
10 {
11 $this->user->delete();
12 
13 $this->close(
14 andForget: [
15 EditUser::class,
16 ]
17 );
18 }
19 
20 public function render()
21 {
22 return view('livewire.delete-user');
23 }
24}

This will remove all existing EditUser modal from the history. Suppose you want to be more explicit and only remove the EditUser modal for the user you’ve just deleted. In that case, you can pass the component parameters that must match for the modal to be removed from the history.

1public function confirmDelete()
2{
3 $this->user->delete();
4 
5 $this->close(
6 andForget: [
7 EditUser::class => ['user' => $this->user->id],
8 ]
9 );
10}

Emitting events

When closing your modal, you would likely want to emit events; for example, when you use a modal to delete a user, you wish to update your user overview to ensure the deleted user is no longer listed. Let’s take a look at how we can achieve this.

1class DeleteUser extends Modal
2{
3 public int|User $user;
4 
5 public function mount(User $user) {
6 $this->user = $user;
7 }
8 
9 public function confirmDelete()
10 {
11 $this->user->delete();
12 
13 $this->close(
14 andEmit: [
15 'userDeleted'
16 ]
17 );
18 }
19 
20 public function render()
21 {
22 return view('livewire.delete-user');
23 }
24}

Alternatively, if you want to emit events to a specific component and pass parameters to your event, you can use the following syntax:

1public function confirmDelete()
2{
3 $this->user->delete();
4 
5 $this->close(
6 andEmit: [
7 // Emit globally
8 'userDeleted' => ['param1', 'param2'],
9 // Emit the event to the UsersOverview component
10 UsersOverview::class => ['userDeleted', ['param1', 'param2']],
11 ]
12 );
13}

Listening to events works just like any other Livewire component:

1class UsersOverview extends Modal
2{
3 public function getListeners()
4 {
5 return ['userDeleted' => '$refresh']; // Refresh the component
6 }
7 
8 public function render()
9 {
10 return view('livewire.users-overview');
11 }
12}
To navigate
Press Enter to select
Documentation
/