microweber-packages / microweber-filament-modal-teleport
Fixes inline Filament action modals rendered un-clickable because the focus-trap marks an ANCESTOR (.fi-main) `inert`, which propagates into the modal. Clears the stray inert in place (no DOM move, so Livewire wire:model/wire:submit keep working). Self-healing MutationObserver; supports nested/stack
Package info
github.com/microweber-packages/microweber-filament-modal-teleport
pkg:composer/microweber-packages/microweber-filament-modal-teleport
Requires
- php: ^8.1
- illuminate/support: ^10.0|^11.0|^12.0|^13.0
- microweber-packages/microweber-package: *
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- filament/filament: ^3.0|^4.0|^5.0
- livewire/livewire: ^3.0|^4.0
- orchestra/testbench: ^8.0|^9.0|^10.0
- phpunit/phpunit: ^10.0|^11.0
Suggests
- filament/filament: Required for Filament panel integration
- livewire/livewire: Required for Livewire component testing
Provides
None
Conflicts
None
Replaces
- microweber-packages/filament-modal-teleport: *
This package is auto-updated.
Last update: 2026-11-03 17:06:35 UTC
README
Makes inline Filament action modals clickable by clearing the stray inert that traps them — in place, without moving the DOM.
Package id/namespace keep the historical
modal-teleportname; the mechanism isinertneutralization (DOM teleport was tried and rejected — see below).
The Problem
When a Filament modal opens, its focus trap marks the background content inert so nothing behind the modal is interactive or focusable. Normally Filament teleports the modal to the top of the panel first, so it sits outside the inerted region.
But form / schema-action modals (e.g. an "Apply template" action rendered from a page form) render inline inside .fi-main, and are not teleported. So .fi-main — an ancestor of the modal — receives inert, and inert propagates down into the modal itself.
Result: the modal is visible but completely non-interactive. Every click over it falls through to the nearest non-inert ancestor (.fi-main-ctn), so the modal looks dead — elementFromPoint() over the modal returns .fi-main-ctn, and even a real click never reaches the buttons.
The Solution
Whenever an element that contains an open modal is marked inert, this package clears the inert on that element:
document.querySelectorAll('[inert]').forEach((el) => { if (elementContainsAnOpenModal(el)) el.removeAttribute('inert'); });
- In place — no DOM relocation. The modal stays inside its Livewire component root, so
wire:model/wire:submitkeep working (verified end-to-end: the action actually runs). - Scoped. Only elements that actually contain an open modal are touched; legitimate
inert(loading overlays, the background sidebar, etc.) is left alone. - Self-healing. A
MutationObserver(filtered to theinertattribute) re-applies the fix if Filament re-addsinerton a later update. - The modal's own Alpine focus-trap still keeps focus inside the modal, and its overlay still blocks background clicks, so only the modal itself is re-enabled.
Why not the "obvious" fixes
Both were implemented and rejected after in-browser verification:
| Attempt | Result |
|---|---|
CSS stacking-context neutralization (opacity:1 / transform:none / filter:none / contain / z-index) |
No effect. inert is not a CSS property; the modal is fixed z:40 in the root stacking context with zero stacking triggers on any ancestor, yet still un-hittable. |
DOM teleport of .fi-modal out of .fi-main |
Makes it clickable, but the Livewire component root (.fi-page) is nested inside .fi-main-ctn, so moving the modal out severs its wire:model/wire:submit binding — the action silently no-ops (verified: the template did not apply). |
Installation
// In your Filament PanelProvider: use MicroweberPackages\FilamentModalTeleport\ModalTeleportPlugin; $panel->plugin(ModalTeleportPlugin::make());
The plugin registers a PanelsRenderHook::BODY_END hook (in register(), so it is flushed to Filament's render-hook registry before the page renders) that injects the JS automatically.
Supported scenarios
- ✅ Centered modals · SlideOver modals · nested / stacked modals (N levels)
- ✅ Filament v3 / v4 / v5 (
.fi-modal/.fi-mainandinertfocus-trap are core) - ✅ Any Filament project (not Microweber-specific — the fix is not hardcoded to
.fi-main; it targets whatever inerted ancestor contains an open modal)
License
MIT