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

Magnific Popup Laravel Package

dimsemenov/magnific-popup

Magnific Popup is a fast, lightweight, responsive lightbox plugin for jQuery that displays images, galleries, videos, iframes, AJAX and inline content with smooth CSS animations, a modular API, and retina-ready mobile support.

Deep Wiki
Context7

Getting Started

Magnific Popup is a front-end jQuery plugin, not a Laravel package — there is no service provider, no config file, and no PHP surface. Treat it as a static asset dependency and budget your integration work in resources/js and Blade only.

  1. Install as a dependency
npm i jquery magnific-popup
  1. Wire jQuery onto window before importing the plugin. The plugin is a UMD bundle that augments $.fn, so import order matters:
// resources/js/app.js
import $ from 'jquery';
window.$ = window.jQuery = $;          // needed for inline Blade scripts + Alpine

import 'magnific-popup';
import 'magnific-popup/dist/magnific-popup.css'; // verify exact filename in node_modules/magnific-popup/dist
  1. Render a trigger from Blade. The plugin reads href (or data-mfp-src) as the target:
<a href="{{ Storage::url($photo->path) }}"
   class="js-lightbox"
   title="{{ $photo->caption }}">
    <img src="{{ Storage::url($photo->thumb_path) }}" alt="{{ $photo->caption }}">
</a>
  1. Initialise once, delegated. Rather than initialising per element, use a single call with delegate so items added by Livewire, infinite scroll, or pagination keep working:
$('.js-gallery').magnificPopup({
    delegate: 'a.js-lightbox',
    type: 'image',
    gallery: { enabled: true, preload: [0, 2] },
    mainClass: 'mfp-fade',
    removalDelay: 200,
});

Where to look first: the official docs (dimsemenov.com/plugins/magnific-popup) are still the best reference for the options object; node_modules/magnific-popup/dist for shipped CSS/JS filenames; and the data('magnificPopup') instance in devtools for runtime state. First use case: an image gallery on a resource index/show page is the canonical fit — five minutes of work, no server changes.

Implementation Patterns

AJAX popups that load a Blade partial. This is where it pays off in Laravel: a "Quick create" or "Edit" form rendered server-side into the lightbox.

// PhotoController@edit
if ($request->ajax()) {
    return view('photos._form', ['photo' => $photo]); // no layout
}
$('.js-modal-form').magnificPopup({
    type: 'ajax',
    midClick: true,
    closeOnBgClick: false,
    ajax: {
        settings: {
            headers: { 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content },
            dataType: 'html',
        },
    },
    callbacks: {
        ajaxContentAdded() {
            this.content.find('form').on('submit', submitQuickForm);
        },
    },
});

Then on success call $.magnificPopup.close() and refresh the listing — window.location.reload(), an axios table reload, or Livewire.dispatch('photo-saved'). Note $request->ajax() depends on the X-Requested-With header; Magnific sets it by default, but pass it explicitly if you have custom middleware.

Inline markup instead of a remote fetch. Wrap a <template> or hidden <div id="inline-popup"> and use type: 'inline' with data-mfp-src="#inline-popup". Good for confirmations and short Alpine-driven forms where a round trip is wasteful.

Video and iframe content. type: 'iframe' accepts a patterns object for YouTube/Vimeo URL rewriting; iframe.markup lets you replace the wrapper with your own responsive-embed classes so it plays nicely with Tailwind's aspect utilities.

Reusable JS module. Keep the options in resources/js/lightbox.js and export an initLightbox(root = document) function; call it on DOMContentLoaded, livewire:navigated, and after Livewire.hook('morph.updated'). Guard with if (!el.data('magnificPopup')) to avoid double-initialising.

Analytics and side effects via callbacks. open, close, change, and elementParse fire with this bound to the instance (this.currItem, this.content). Use change to log gallery navigation — cleaner than wiring click handlers on every thumbnail.

Gotchas and Tips

  • Duplicate jQuery. Vite usually dedupes, but if the plugin silently no-ops, you have two jQuery instances. Confirm window.jQuery.fn.magnificPopup exists in the console before debugging further. Add resolve: { dedupe: ['jquery'] } in vite.config.js.
  • Tailwind preflight fights the CSS. Button resets and box-sizing changes can shift the close button and arrows. Import magnific-popup.css after your Tailwind layer, and expect to touch .mfp-* rules. Also raise z-index if you use Bootstrap/Tailwind modals: .mfp-bg, .mfp-wrap { z-index: 9999; }.
  • Inline content is reparented. Magnific moves the element into the popup container and puts it back on close. Livewire components, Alpine x-data roots, and delegated listeners inside that subtree can lose bindings or re-initialise on close. Prefer type: 'ajax' for anything stateful.
  • Animation requires two options. mainClass alone does nothing visible; you need removalDelay to match your CSS transition, otherwise the popup closes instantly.
  • Re-initialisation on dynamic content. With delegate, new elements work automatically — without it, you must re-init after every render. This is the single most common Livewire bug report.
  • Accessibility is not built in. No focus trap, no aria-modal, no focus restoration. Add role="dialog"/aria-modal="true" via callbacks.open, store document.activeElement, and restore it in close. If a11y is a hard requirement, evaluate GLightbox or Fancybox instead.
  • AJAX content is injected as raw HTML. Magnific does not sanitise anything. Never pass user-controlled URLs into type: 'iframe' (open-redirect/XSS), and only load popup content from your own routes.
  • CSP. The plugin sets inline style attributes and data-URI spinners; a strict style-src will break positioning and the loading indicator. Budget for style-src 'unsafe-inline' or hash-based exceptions.
  • Mobile positioning. If you see jumpy scrolling or clipped content on iOS, set fixedContentPos: false and overflowY: 'auto'.
  • Testing with Dusk. The popup only becomes interactable when the container gains .mfp-ready. Assert ->waitFor('.mfp-ready') before touching .mfp-content children, and remember the content is outside your page root.
  • Extension points. $.magnificPopup.registerModule(name, { options, proto: {...} }) is the documented way to add a content type or behaviour; subclass an existing module rather than monkey-patching callbacks.
  • Project risk. The plugin is effectively feature-frozen and jQuery-bound. Adding ~30 KB gzipped of jQuery to a modern Laravel/Vite stack is a real cost — if you have no other jQuery dependency and only need an image lightbox, a dependency-free alternative is usually the better trade. If you already ship jQuery, Magnific remains stable, tiny, and predictable.
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.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums