Modal
Modal overlay component for displaying content in a centered dialog with backdrop
Basic Usage
The most basic modal with Livewire entangle:
<neura::button wire:click="$set('showModal', true)">
Open Modal
</neura::button>
<neura::modal entangle="showModal">
<neura::modal.header>
<neura::heading level="h3">Modal Title</neura::heading>
</neura::modal.header>
<neura::modal.body>
<p>Modal content goes here</p>
</neura::modal.body>
<neura::modal.footer>
<neura::button wire:click="$set('showModal', false)">
Close
</neura::button>
</neura::modal.footer>
</neura::modal>
With Livewire ModalComponent
Create a modal component by extending
Neura\Kit\Support\Modal\ModalComponent. This provides a clean way to create reusable modal components:
This is a live example of a modal component created with
ModalComponent. Click the button above to see it in action.
Creating a Modal Component
Use the
neura-kit:make-modal command to create a new modal component:
php artisan neura-kit:make-modal UserModal
This creates a modal component class that extends
ModalComponent:
<?php
namespace App\View\Pages\Backend\Users;
use Neura\Kit\Support\Modal\ModalComponent;
use Illuminate\Contracts\View\View;
class UserModal extends ModalComponent
{
public $userId = null;
public $name = '';
public $email = '';
public function mount($userId = null)
{
if ($userId) {
$user = \App\Models\User::find($userId);
$this->userId = $user->id;
$this->name = $user->name;
$this->email = $user->email;
}
}
public function save()
{
// Save logic here
$this->closeModal();
}
public function render(): View
{
return view('pages.backend.users.user-modal');
}
}
Then use it in your Blade view:
<!-- Open modal with component -->
<neura::button
wire:click="$wire.modal('pages.backend.users.user-modal').open()"
>
Open User Modal
</neura::button>
<!-- Open modal with arguments -->
<neura::button
wire:click="$wire.modal('pages.backend.users.user-modal').with(['userId' => 1]).open()"
>
Edit User
</neura::button>
<!-- Open modal with custom attributes -->
<neura::button
wire:click="$wire.modal('pages.backend.users.user-modal').with(['userId' => 1]).maxWidth('lg').open()"
>
Edit User (Large)
</neura::button>
The modal view should use the modal sub-components:
<!-- resources/views/pages/backend/users/user-modal.blade.php -->
<div>
<neura::modal.header>
<neura::heading level="h3" size="md">
{{ $userId ? 'Edit User' : 'Create User' }}
</neura::heading>
</neura::modal.header>
<neura::modal.body>
<div class="space-y-4">
<neura::input wire:model="name" label="Name" />
<neura::input wire:model="email" type="email" label="Email" />
</div>
</neura::modal.body>
<neura::modal.footer>
<neura::button variant="ghost" wire:click="closeModal">
Cancel
</neura::button>
<neura::button variant="primary" wire:click="save">
{{ $userId ? 'Update' : 'Create' }}
</neura::button>
</neura::modal.footer>
</div>
With Livewire Entangle
Use entangle to sync state with Livewire:
<neura::modal entangle="showModal">
<!-- Modal content -->
</neura::modal>
Modal Sizes
The modal supports different sizes to adjust the maximum width:
<neura::modal size="sm" entangle="showModal">...</neura::modal>
<neura::modal size="md" entangle="showModal">...</neura::modal>
<neura::modal size="lg" entangle="showModal">...</neura::modal>
<neura::modal size="xl" entangle="showModal">...</neura::modal>
<neura::modal size="2xl" entangle="showModal">...</neura::modal>
<neura::modal size="3xl" entangle="showModal">...</neura::modal>
<neura::modal size="4xl" entangle="showModal">...</neura::modal>
<neura::modal size="5xl" entangle="showModal">...</neura::modal>
<neura::modal size="6xl" entangle="showModal">...</neura::modal>
<neura::modal size="7xl" entangle="showModal">...</neura::modal>
<neura::modal size="full" entangle="showModal">...</neura::modal>
Custom Width with ModalComponent
When using ModalComponent, you can specify custom widths using the
attrs() method with maxWidth:
Predefined Sizes
Use predefined Tailwind sizes for optimal performance:
<!-- Using predefined sizes (Tailwind classes) -->
$this->modal(UserModal::class)
->maxWidth('sm') // max-w-sm (384px)
->open();
$this->modal(UserModal::class)
->maxWidth('md') // max-w-md (448px) - Default
->open();
$this->modal(UserModal::class)
->maxWidth('lg') // max-w-lg (512px)
->open();
$this->modal(UserModal::class)
->maxWidth('xl') // max-w-xl (576px)
->open();
$this->modal(UserModal::class)
->maxWidth('2xl') // max-w-2xl (672px)
->open();
$this->modal(UserModal::class)
->maxWidth('3xl') // max-w-3xl (768px)
->open();
$this->modal(UserModal::class)
->maxWidth('4xl') // max-w-4xl (896px)
->open();
$this->modal(UserModal::class)
->maxWidth('5xl') // max-w-5xl (1024px)
->open();
$this->modal(UserModal::class)
->maxWidth('6xl') // max-w-6xl (1152px)
->open();
$this->modal(UserModal::class)
->maxWidth('7xl') // max-w-7xl (1280px)
->open();
$this->modal(UserModal::class)
->maxWidth('full') // max-w-full (100%)
->open();
Custom Width Values
For precise control, use custom width values with units:
<!-- Using custom width values (inline style) -->
// Pixels
$this->modal(UserModal::class)
->maxWidth('600px')
->open();
// Percentage
$this->modal(UserModal::class)
->maxWidth('80%')
->open();
// REM units
$this->modal(UserModal::class)
->maxWidth('50rem')
->open();
// Viewport width
$this->modal(UserModal::class)
->maxWidth('90vw')
->open();
Custom Tailwind Classes
Override with custom Tailwind classes using
maxWidthClass:
<!-- Using custom Tailwind class -->
$this->modal(UserModal::class)
->attrs(['maxWidthClass' => 'max-w-[800px]'])
->open();
$this->modal(UserModal::class)
->attrs(['maxWidthClass' => 'max-w-screen-lg'])
->open();
Performance Tip
Use predefined sizes (sm, md, lg, etc.) when possible as they use Tailwind classes that are already optimized and purged. Custom values use inline styles which are fine but slightly less efficient.
Modal Sections
The modal is composed of three main sections: header, body, and footer:
Header
Body
Footer
<neura::modal entangle="showModal">
<neura::modal.header>
<neura::heading>Title</neura::heading>
</neura::modal.header>
<neura::modal.body>
<!-- Content -->
</neura::modal.body>
<neura::modal.footer>
<!-- Actions -->
</neura::modal.footer>
</neura::modal>
Footer Alignment
Align footer buttons with the align attribute:
<neura::modal.footer align="left">...</neura::modal.footer>
<neura::modal.footer align="center">...</neura::modal.footer>
<neura::modal.footer align="right">...</neura::modal.footer>
<neura::modal.footer align="between">...</neura::modal.footer>
Closeable Header
Disable the close button in the header with closeable="false":
<neura::modal.header :closeable="false">
<neura::heading>Title</neura::heading>
</neura::modal.header>
Persistent Modal
Prevent closing the modal with persistent="true" (cannot be closed with Escape or backdrop):
<neura::modal entangle="showModal" :persistent="true">
<!-- Modal content -->
</neura::modal>
Close Options
Control how the modal can be closed:
Disable Backdrop Close
Disable Escape Close
<!-- Disable closing on backdrop click -->
<neura::modal :closeOnBackdrop="false" entangle="showModal">...</neura::modal>
<!-- Disable closing with Escape -->
<neura::modal :closeOnEscape="false" entangle="showModal">...</neura::modal>
Nested Modals (Modal Stack)
The modal system supports opening modals from within other modals. When you open a new modal, the current one is preserved in a stack. When you close the new modal, you're automatically returned to the previous one.
Modal Stack Behavior
Opening Modal B from Modal A pushes A onto the stack. Closing Modal B pops A from the stack and displays it again with preserved state and focus.
Click to open the first modal, then navigate through the stack by opening subsequent modals. Close each modal to navigate back through the stack.
How It Works
From within a modal component, simply call
$this->modal() to open another modal. The current modal will be preserved and restored when the new modal is closed.
<?php
namespace App\View\Modals;
use Neura\Kit\Support\Modal\ModalComponent;
class FirstModal extends ModalComponent
{
public function openSecondModal()
{
// Opens SecondModal while preserving FirstModal in the stack
$this->modal(SecondModal::class)->open();
}
public function render()
{
return view('modals.first-modal');
}
}
In the Blade view, simply call the method to open the next modal:
<!-- resources/views/modals/first-modal.blade.php -->
<div>
<neura::modal.header>
<neura::heading level="h3" size="md">First Modal</neura::heading>
</neura::modal.header>
<neura::modal.body>
<p>This is the first modal in the stack.</p>
</neura::modal.body>
<neura::modal.footer>
<neura::button variant="ghost" wire:click="closeModal">
Close
</neura::button>
<neura::button variant="primary" wire:click="openSecondModal">
Open Second Modal
</neura::button>
</neura::modal.footer>
</div>
Stack Navigation
1
User opens Modal A from the page
2
User opens Modal B from Modal A → A is pushed to stack
3
User opens Modal C from Modal B → B is pushed to stack
4
User closes Modal C → Modal B is restored from stack
5
User closes Modal B → Modal A is restored from stack
6
User closes Modal A → All modals closed, back to page
Use Cases
Confirmation Modal
Form Modal
Best Practices
✓ Do
- Use modals for important actions that require user attention
- Always provide a clear way to close the modal (close button or Cancel button)
- Use appropriate sizes based on content (don't use a modal that's too wide for little content)
- Organize content with header, body, and footer for a clear structure
- Use entangle with Livewire for better state synchronization
✗ Don't
- Don't create modals that are too wide or contain too much information
- Don't use persistent modals unless absolutely necessary
- Don't forget to provide a way to close the modal
- Don't use modals for content that could be on the page
- Don't nest more than 3 modals deep (can be confusing for users)
Properties
| Property | Type | Default | Description |
|---|---|---|---|
| name | string|null | null | Modal name for management with Livewire (uses modals.{name}.open) |
| open | bool | false | Initial open state of the modal |
| size | string | 'md' | Modal size. Values: 'xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl', '5xl', '6xl', '7xl', 'full' |
| closeable | bool | true | Display close button in header |
| persistent | bool | false | Prevents closing with Escape or backdrop |
| closeOnBackdrop | bool | true | Allow closing by clicking on backdrop |
| closeOnEscape | bool | true | Allow closing with Escape key |
| entangle | string|null | null | Livewire property to sync with open state (e.g., "showModal") |
| maxWidth | string|null | null | Custom maximum width (e.g., "800px", "50rem") - overrides size prop if set |
Modal Sub-components Properties
Header Properties
| Property | Type | Default | Description |
|---|---|---|---|
| closeable | bool | true | Display close button in header |
Body Properties
| Property | Type | Default | Description |
|---|---|---|---|
| padding | bool | true | Add padding to body (p-6) |
Footer Properties
| Property | Type | Default | Description |
|---|---|---|---|
| align | string | 'right' | Button alignment. Values: 'left', 'center', 'right', 'between' |