Learn everything there is to know about the Modal Component.
Add the component service provider to your config/app.php
to ensure the required assets are loaded.
1'providers' => [ 2 3 /* 4 * Laravel Framework Service Providers... 5 */ 6 Illuminate\Auth\AuthServiceProvider::class, 7 8 /* 9 * Package Service Providers...10 */11 WireElements\Pro\Components\Modal\ModalServiceProvider::class,12]
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 9 @livewireStyles10</head>11<body>12 13 <!-- Require the Modal Pro component -->14 @livewire('modal-pro')15 16 @livewireScripts17</body>18</html>
Add the @livewire('modal-pro')
directive to your layout.
This component requires some additional Javascript so ensure this is compiled by requiring the script in your resources/js/bootstrap.js
:
1import '../../vendor/wire-elements/pro/resources/js/overlay-component.js'
It’s also possible to include the required resources directly; see the following next step.
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-assets2 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 9 <!-- Include the overlay-component.css stylesheet -->10 <link rel="stylesheet" href="{{ asset('vendor/wire-elements-pro/css/bootstrap-overlay-component.css') }}">11 12 @livewireStyles13</head>14<body>15 16 <!-- //.... -->17 18 <!-- Include the overlay-component.js script -->19 <script src="{{ asset('vendor/wire-elements-pro/js/overlay-component.js') }}"></script>20</body>21</html>
Make sure to republish assets when you update the package.
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@import "../../vendor/wire-elements/pro/resources/css/tailwind/overlay-component.css"; 2@tailwind base; 3@tailwind components; 4@tailwind utilities; 5 6// Add your customizations here 7 8// Example: Disable the transition animation when reduced motion is enabled 9.wep-modal-content,10.wep-slide-over-container-inner-wrap {11 @apply motion-reduce:transition-none;12}
Add the import statement to your resources/css/app.css
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-config2 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.
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];
You create a Livewire component as you would regularly do to get started. For example, by running the make
command:
1php artisan livewire:make UsersOverview2 3COMPONENT CREATED 🤙4 5CLASS: app/Http/Livewire/UsersOverview.php6VIEW: 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> 8 </div> 9 10 <x-slot name="buttons">11 <button type="submit">12 Save Changes13 </button>14 <button type="button" wire:click="$dispatch('modal.close')">15 Cancel16 </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.
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(): array13 {14 return [];15 }16 17 public static function attributes(): array18 {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(): array13 {14 return [15 // Close the modal if the escape key is pressed16 'close-on-escape' => true,17 // Close the modal if someone clicks outside the modal18 '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 modal22 'remove-state-on-close' => false,23 ];24 }25 26 public static function attributes(): array27 {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, fullscreen31 'size' => '2xl',32 ];33 }34}
Context | Method |
---|---|
Javascript |
|
Blade |
|
Blade & Livewire directive |
|
Inside a Livewire Component View |
|
Inside a Livewire Component Class |
|
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 |
|
Blade |
|
Blade & Livewire directive |
|
Inside a Livewire Component View |
|
Inside a Livewire Component Class |
|
It’s also possible to override the modal behavior and attributes when opening a modal by passing a fourth and fifth argument:
1Livewire.dispatch('modal.open', {component: 'edit-user', arguments: {"user": 1}, elementAttributes: {"size":"2xl"}, elementBehavior: {"close-on-escape": false}});
To close your modal you can use a similar syntax as opening a modal.
Context | Method |
---|---|
Javascript |
|
Blade |
|
Blade & Livewire directive |
|
Inside a Livewire Component View |
|
Inside a Livewire Component Class |
|
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.dispatch('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}
When closing your modal, you would likely want to dispatch 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 andDispatch: [15 'userDeleted'16 ]17 );18 }19 20 public function render()21 {22 return view('livewire.delete-user');23 }24}
Alternatively, if you want to dispatch 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 andDispatch: [ 7 // Dispatch globally 8 'userDeleted' => ['param1', 'param2'], 9 // Dispatch the event to the UsersOverview component10 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}
Wire Elements Pro ships with an opinionated confirmation modal you can use when you want to ask your users for confirmation.
All you have to do in order to use this feature is to include the InteractsWithConfirmationModal
trait.
1use WireElements\Pro\Concerns\InteractsWithConfirmationModal; 2 3class UsersOverview extends Modal 4{ 5 use InteractsWithConfirmationModal; 6 7 public function delete($userId) 8 { 9 $this->askForConfirmation(10 callback: function() use ($userId) {11 User::find($userId)?->delete();12 },13 );14 }15 16 public function render()17 {18 return view('livewire.user-overview');19 }20}
Easy right? But that's not all, the confirmation modal ships with additional features. Let's take a look what options are available.
1$this->askForConfirmation( 2 callback: function() use ($userId) { 3 User::find($userId)?->delete(); 4 }, 5 prompt: [ 6 'title' => __('Warning! Destructive action'), 7 'message' => __('Are you sure you want to delete this user?'), 8 'confirm' => __('Yes, Delete'), 9 'cancel' => __('Stop'),10 ],11 tableHeaders: ['Column 1', 'Column 2'],12 tableData: [13 ['Row 1 - Column 1 Value', 'Row 1 - Column 2 value'],14 ['Row 2 - Column 1 Value', 'Row 2 - Column 2 value'],15 ],16 confirmPhrase: 'DELETE',17 theme: 'warning',18 metaData: [19 'custom' => 'meta data'20 ],21 modalBehavior: [22 'close-on-escape' => false,23 'close-on-backdrop-click' => false,24 'trap-focus' => true,25 ],26 modalAttributes: [27 'size' => '2xl'28 ]29);
$theme
to make your changes.
Please be aware that all these properties are public and can be seen by anyone using devtools.
If you want to customize the confirmation modal you can either publish the views or change the view in the wire-elements-pro.php
config file:
1return [ 2 'default' => 'tailwind', 3 4 'components' => [...], 5 6 'presets' => [ 7 'tailwind' => [ 8 'modal' => [ 9 'size-map' => [...],10 'confirmation_view' => 'wire-elements-pro::modal.tailwind.confirmation',11 ]12 ],13 'bootstrap' => [14 'modal' => [15 'size-map' => [...],16 'confirmation_view' => 'wire-elements-pro::modal.bootstrap.confirmation',17 ]18 ],19 ],20]
Please note that the confirmation modal only works if the parent method calling askForConfirmation
consists out of values that can be converted into JSON (integers, strings, and arrays):
1use WireElements\Pro\Concerns\InteractsWithConfirmationModal; 2 3class UsersOverview extends Modal 4{ 5 use InteractsWithConfirmationModal; 6 7 // $userID is an integer or string 8 public function delete($userId) 9 {10 $this->askForConfirmation(11 callback: fn() => User::find($userId)?->delete(),12 );13 }14 15 // Passing an entire object won't work16 public function delete(User $user)17 {18 $this->askForConfirmation(19 callback: fn() => $user->delete(),20 );21 }22}