sobitnl/livewire-modal-sheet

A Livewire 4 modal/bottomsheet component that supports multiple child modals while maintaining state

Installs: 1

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/sobitnl/livewire-modal-sheet

1.0.0 2026-01-21 10:09 UTC

This package is auto-updated.

Last update: 2026-01-21 10:24:48 UTC


README

Alt bottom sheet illustration

A Livewire 4 modal/bottom-sheet component that supports multiple child modals while maintaining state.

Total Downloads Livewire Modal Sheet Latest Stable Version Livewire Modal Sheet License Livewire Modal Sheet

Installation

composer require sobitnl/livewire-modal-sheet

Setup

Add the Livewire directive to your layout file (typically before </body>):

<html>
<body>
    <!-- Your content -->
    
    @livewire('livewire-modal-sheet')
</body>
</html>

TailwindCSS

Add the following to your tailwind.config.js to include the modal styles:

export default {
    content: [
        './vendor/sobitnl/livewire-modal-sheet/resources/views/*.blade.php',
        // ... your other paths
    ],
    safelist: [
        {
            pattern: /max-w-(full|sm|md|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl)/,
            variants: ['full','sm', 'md', 'lg', 'xl', '2xl']
        }
    ],
}

Creating a Modal

Create a Livewire component that extends ModalComponent:

<?php

namespace App\Livewire;

use SobitNL\LivewireModalSheet\ModalComponent;

class EditUser extends ModalComponent
{
    public $user;

    public function mount($userId)
    {
        $this->user = User::findOrFail($userId);
    }

    public function save()
    {
        // Save logic...
        
        $this->closeModal();
    }

    public function render()
    {
        return view('livewire.edit-user');
    }
}

Opening a Modal

You can open a modal by dispatching the openModal event:

<!-- Outside of any Livewire component -->
<button onclick="Livewire.dispatch('openModal', { component: 'edit-user', arguments: { userId: 1 }})">
    Edit User
</button>

<!-- Inside a Livewire component -->
<button wire:click="$dispatch('openModal', { component: 'edit-user', arguments: { userId: {{ $user->id }} }})">
    Edit User
</button>

Passing Parameters

Parameters are automatically injected into your modal component:

class EditUser extends ModalComponent
{
    public User $user; // Automatically resolved from route binding

    public function render()
    {
        return view('livewire.edit-user');
    }
}
<button wire:click="$dispatch('openModal', { component: 'edit-user', arguments: { user: {{ $user->id }} }})">
    Edit User
</button>

Closing a Modal

From the view:

<button wire:click="$dispatch('closeModal')">Cancel</button>

From the component:

public function save()
{
    // Save logic...
    
    $this->closeModal();
}

With events:

public function save()
{
    $this->user->save();
    
    $this->closeModalWithEvents([
        UserList::class => 'refreshList',
    ]);
}

Nested Modals

You can open a modal from within another modal:

<!-- Inside EditUser modal -->
<button wire:click="$dispatch('openModal', { component: 'delete-user', arguments: { user: {{ $user->id }} }})">
    Delete User
</button>

When closing the child modal, it will return to the parent modal.

Force Close All Modals

$this->forceClose()->closeModal();

Skip Previous Modals

$this->skipPreviousModal()->closeModal();
// or skip multiple
$this->skipPreviousModals(2)->closeModal();

Modal Properties

Override these static methods in your modal component:

class EditUser extends ModalComponent
{
    // should it behave as a bottomsheet
    public static function asBottomSheet(): bool
    {
        return true; //default is false
    }
    
    // Modal width: 'full', 'sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl', '5xl', '6xl', '7xl'
    public static function modalMaxWidth(): string
    {
        return 'lg';
    }

    // Close when clicking outside
    public static function closeModalOnClickAway(): bool
    {
        return false;
    }

    // Close when pressing Escape
    public static function closeModalOnEscape(): bool
    {
        return true;
    }

    // Destroy component state on close
    public static function destroyOnClose(): bool
    {
        return true;
    }
}

Configuration

Publish the config file:

php artisan vendor:publish --tag=livewire-modal-sheet-config

Publish the views:

php artisan vendor:publish --tag=livewire-modal-sheet-views

Styling

There are three classes you can use to style the modal and sheet elements:

  • livewire-modal-sheet
    the general modal/ sheet class

  • livewire-modal-sheet-bottom
    specifically for the bottom sheet

  • livewire-modal-sheet-drag-item
    the draggable bottom sheet element

Credits

License

MIT License. See LICENSE for more information.