Back to Home

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'