Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Livewire Slide Overs Laravel Package

laravelcm/livewire-slide-overs

Livewire Slide Over Panel adds stateful drawer (slide-over) components to Laravel Livewire apps, supporting multiple child components while preserving state. Inspired by wire-elements/modal, it installs via Composer and a single @livewire directive.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Requirements: PHP 8.3+, Laravel 11.x/12.x, Livewire 3.4+ or 4.x.
  • Install with Composer:
composer require laravelcm/livewire-slide-overs
  • Publish the config if you need to change global defaults:
php artisan vendor:publish --tag=livewire-slide-over-config
  • Mount the panel host once in your layout, usually just before </body>:
@livewire('slide-over-panel')
  • If you use Tailwind, make sure the package views are scanned. Tailwind v4:
@import "tailwindcss";
@source "../vendor/laravelcm/livewire-slide-overs/resources/views";

Tailwind v3:

content: [
  './vendor/laravelcm/livewire-slide-overs/resources/views/**/*.blade.php',
]

If you do not use Tailwind, set include_css => true in the published config.

  • First practical use case: an “Edit User” drawer. Generate a normal Livewire component, then extend SlideOverComponent:
namespace App\Livewire;

use App\Models\User;
use Laravelcm\LivewireSlideOvers\SlideOverComponent;

class EditUser extends SlideOverComponent
{
    public User $user;

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

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

Open it from an existing Livewire component:

<button wire:click="$dispatch('openPanel', { component: 'edit-user', arguments: { user: {{ $user->id }} } })">
    Edit user
</button>

Start by reading the README’s “Opening a Slide Over”, “Passing Data”, and “Component Properties” sections, then check the published config. If you are upgrading from v1, read the v2.0.0 changelog first because it contains breaking changes.

Implementation Patterns

Open from Livewire, Blade, or JavaScript. The event name is openPanel. Use Livewire dispatch inside components and Livewire.dispatch outside:

<!-- Inside Livewire -->
<button wire:click="$dispatch('openPanel', { component: 'shopping-cart' })">Cart</button>

<!-- Outside Livewire -->
<button onclick="Livewire.dispatch('openPanel', { component: 'shopping-cart' })">Cart</button>

Use dot notation for namespaced components:

<button wire:click="$dispatch('openPanel', { component: 'shop.actions.shopping-cart' })">
    Cart
</button>

Use $slideOver.open() when perceived latency matters. It opens the drawer chrome immediately while Livewire hydrates the content:

<button onclick="$slideOver.open('edit-user', { user: {{ $user->id }} })">
    Edit user
</button>

The first open of a component in a session falls back to a normal round-trip so the package can resolve width/position attributes. Those attributes are then cached in sessionStorage; later opens are instant. To make the very first open instant, pass panel overrides explicitly:

<button onclick="$slideOver.open('shopping-cart', {}, { maxWidthClass: 'max-w-2xl' })">
    View cart
</button>

Pass data through arguments and let Livewire resolve models. Argument names should match mount() parameters. Type-hinting an Eloquent model and passing the ID works as expected:

<button wire:click="$dispatch('openPanel', { component: 'edit-user', arguments: { user: {{ $user->id }} } })">
    Edit user
</button>
public function mount(User $user)
{
    $this->user = $user;
}

Configure per-component behavior with static methods. This is the normal way to set width and close behavior without touching global config:

public static function panelMaxWidth(): string
{
    return '2xl'; // suffix only: sm, md, lg, xl, 2xl, ... 7xl
}

public static function closePanelOnClickAway(): bool
{
    return false;
}

public static function closePanelOnEscape(): bool
{
    return true;
}

public static function closePanelOnEscapeIsForceful(): bool
{
    return false; // ESC pops only the active panel instead of force-closing all
}

public static function destroyOnClose(): bool
{
    return true;
}

Resize the open panel dynamically. This is useful for progressive disclosure without closing/reopening:

public function loadDetails(): void
{
    // fetch data...

    $this->resizePanel('max-w-6xl');
}

public function clearDetails(): void
{
    $this->resizePanel('max-w-2xl');
}

You can target a specific stacked panel by passing its ID as the second argument:

$this->resizePanel('max-w-4xl', $panelId);

Manage stacked panels deliberately. The package supports multiple children/panels and preserves state. Common workflow patterns:

// Close just the current panel
$this->closePanel();

// Close everything
$this->forceClose()->closePanel();

// Go back past one or more panels
$this->skipPreviousPanel()->closePanel();
$this->skipPreviousPanels(2)->closePanel();

// Skip and discard skipped component state
$this->skipPreviousPanels(2)->destroySkippedPanels()->closePanel();

Refresh parent Livewire components with close events. Instead of manually wiring browser events, emit when closing:

$this->closePanelWithEvents(['refreshList']);

$this->closePanelWithEvents([
    'user-table' => 'refreshList',
]);

$this->closePanelWithEvents([
    ['refreshList', ['user' => $this->user->id]],
]);

dispatchCloseEvent() on the component can also be set to true if you want a close event dispatched automatically.

Stacked-panel configuration. v2.0.0 introduced stacked panels with a config option such as 'stack' => true. Per-component position can be set through panel attributes. Use this when building workflows like “list → detail → edit” without losing the previous panel’s state.

Gotchas and Tips

  • panelMaxWidth() is not the same format as resizePanel(). panelMaxWidth() returns a suffix like '2xl', while resizePanel() expects a Tailwind class like 'max-w-6xl'. The $slideOver.open() override uses maxWidthClass: 'max-w-2xl'. Mixing these up is an easy source of silent width bugs.

  • Tailwind must see the package views. If the drawer renders unstyled or widths do not apply, check @source/content configuration first. If you do not use Tailwind, set include_css => true. v2.0.3 added safelisting for Tailwind v4 max-width classes, but arbitrary JIT values such as max-w-[800px] may still need explicit safelisting in your app.

  • First open may feel slower than later opens. This is expected when using $slideOver.open() without attributes because the panel cannot animate until it knows width/position. The result is cached in sessionStorage. Pass the third argument if the first open must be instant. Also remember that changing component defaults during a session can leave stale cached attributes until the session cache is cleared.

  • State is preserved by default. The config default for destroy_on_close is false. If you expect a fresh form every time a drawer opens, set destroyOnClose() to true on that component, or use destroySkippedPanels() when skipping stacked panels.

  • Escape behavior can surprise you in stacks. The default close_slide_over_on_escape_is_forceful is true, which means ESC can close all panels. If you want ESC to pop only the active panel, override closePanelOnEscapeIsForceful() to return false. The v2.0.0 changelog calls out improved stacked ESC behavior, so verify behavior on your installed version.

  • Close events are not emitted by default. dispatchCloseEvent() defaults to false. If a parent table or dashboard needs to refresh after a drawer saves, either set dispatchCloseEvent() to true or use closePanelWithEvents() with the target component/event.

  • Do not disable package JS unless you replace it. include_js defaults to true. If you set it to false, you must import or provide the package JavaScript yourself; otherwise helper methods and panel animations will not work.

  • Upgrading to v2.0.0+ is not completely transparent. Breaking changes include PanelContract defining method signatures, component ID hashing moving from serialize() to json_encode(), and listeners moving to #[On] attributes. Review these if you extended internal classes, relied on component IDs, or had custom event listeners.

  • Namespace component names carefully. If a component lives in App\Livewire\Shop\Actions\ShoppingCart, open it as shop.actions.shopping-cart. A wrong component name usually looks like a missing component or a panel that never hydrates. Check the network response and the dispatched component payload first.

  • v2.1.0 adds native dialog mode and dynamic resize. If you need the newer resize behavior or native dialog semantics, make sure you are on v2.1.0+. Older versions will not have these features even if the README examples look similar.

  • Debugging order: confirm @livewire('slide-over-panel') is present in the layout, confirm the openPanel payload component name and arguments, confirm Tailwind is scanning package views, then inspect the Livewire request/response and sessionStorage if using $slideOver.open(). Most day-to-day issues are component-name, Tailwind scanning, or width-format mistakes.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log