sanzgrapher/filament-draggable-modal
Installation:
composer require sanzgrapher/filament-draggable-modal
Ensure your project uses Filament v5 (compatibility is explicitly stated).
Registration:
Add the plugin to your Panel in app/Providers/Filament/AdminPanelProvider.php:
public function panel(Panel $panel): Panel
{
return $panel
->plugin(DraggableModalPlugin::make());
}
First Use Case: Open any modal in your Filament admin panel (e.g., create/edit forms, confirmation dialogs). The modal header should now be draggable by default—no additional code required.
Zero-Configuration Activation: The plugin auto-detects and enhances all modals in Filament v5. No need to manually mark specific modals for draggability.
Integration with Custom Modals:
If using custom modal components (e.g., via Modal facade or Modal::make()), ensure they extend Filament’s base modal structure. The plugin targets standard Filament modal classes by default.
Conditional Activation:
Disable draggability for specific modals by adding a data-draggable="false" attribute to the modal’s root element:
<x-modal data-draggable="false">
<!-- Modal content -->
</x-modal>
Dynamic Handle Customization: Override the draggable handle (e.g., make the entire header draggable or add a custom grip):
// In a custom JS file (e.g., via Filament's asset pipeline)
document.addEventListener('DOMContentLoaded', () => {
const modal = document.querySelector('[data-modal]');
if (modal) {
modal.setAttribute('data-draggable-handle', '.custom-handle-class');
}
});
Responsive Behavior:
Disable dragging on mobile devices by checking window.innerWidth in a custom script:
if (window.innerWidth <= 768) {
document.querySelectorAll('[data-modal]').forEach(modal => {
modal.setAttribute('data-draggable', 'false');
});
}
Event Listeners:
Listen for drag events to trigger custom logic (e.g., save modal position in localStorage):
document.addEventListener('draggableModalDragged', (e) => {
const { modalId, position } = e.detail;
localStorage.setItem(`modal-${modalId}-position`, JSON.stringify(position));
});
Note: Requires extending the plugin’s JS (see Extension Points).
Filament Version Mismatch:
filament/filament package version in composer.json (≥5.0.0).CSS Conflicts:
position: fixed or overflow: hidden on parent containers may prevent dragging.pointer-events: none to conflicting parents or adjust z-index.Nested Modals:
data-draggable="false".Performance with Many Modals:
Check Plugin Registration:
Ensure DraggableModalPlugin::make() is called after ->id() and before ->discoverResources()/->discoverPages() in your panel() method.
Console Errors:
Open DevTools (F12) and check for errors like:
Uncaught TypeError: modal.addEventListener is not a function
→ Likely a Filament modal not being properly initialized. Update Filament or the plugin.Cannot read property 'setAttribute' of null
→ The modal DOM isn’t ready. Wrap your custom JS in DOMContentLoaded.Visual Glitches:
z-index of the modal or its handle.Custom Drag Logic: Extend the plugin’s JavaScript by publishing its assets:
php artisan vendor:publish --tag=filament-draggable-modal-assets
Then override resources/js/filament-draggable-modal.js and add your logic.
Server-Side Position Storage:
Save modal positions to the database by hooking into Filament’s Saving event:
use Filament\Notifications\Actions\Action;
use Filament\Notifications\Notification;
public function register(): void
{
Notification::macro('saveModalPosition', function ($modalId, $position) {
// Save to DB or cache
});
}
Accessibility: Add ARIA attributes for screen readers:
// In your custom JS
modal.setAttribute('aria-grabbed', 'false');
handle.addEventListener('mousedown', () => {
modal.setAttribute('aria-grabbed', 'true');
});
Default Position Reset: Reset all modal positions to default on login/logout:
use Illuminate\Support\Facades\Event;
Event::listen('filament.auth.login', function () {
session()->forget('modal_positions');
});
Dark Mode Compatibility: Ensure the drag handle’s color contrasts in dark mode by adding:
[data-draggable-handle] {
background-color: rgba(var(--gray-800), 0.5);
}
Performance Optimization: Use passive event listeners for drag events:
modal.addEventListener('mousemove', handler, { passive: true });
How can I help you explore Laravel packages today?