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

Laravel Sweetalert2 Laravel Package

amjadiqbal/laravel-sweetalert2

A Laravel wrapper for SweetAlert2 that lets you fire toasts and modal alerts from your controllers using simple flash helpers. It ships with Blade directives, sensible defaults, and publishable config for quick, customizable notifications.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a fresh, actively maintained rewrite (amjadiqbal/laravel-sweetalert2) — not an upgrade path from the unpublished amjadiqbal/sweetalert2. Treat it as a new install.

Install and wire it up (3 steps):

composer require amjadiqbal/laravel-sweetalert2
php artisan vendor:publish   # publish the config (default / toast / confirm blocks)

Then add the asset directive once, in your main layout, just before </body>:

@vite(['resources/js/app.js'])
@sweetalert2

The <x-sweetalert2 /> component is the equivalent — use whichever fits your Blade style. Without one of these in the layout, nothing renders and nothing warns you (see Gotchas).

Look here first:

  1. config/laravel-sweetalert2.php — default, toast and confirm option blocks are the fastest way to brand every popup in the app at once.
  2. The @sweetalert2 directive/component view — confirms the CDN version, SRI hash and nonce behaviour actually shipping.
  3. php artisan about — shows the installed package version and a support link, handy when a client reports "the popup looks wrong".

First use case — the flash-and-redirect you'll write a hundred times:

public function store(StorePostRequest $request)
{
    Post::create($request->validated());

    swal()->success('Saved', 'Your post is live.');

    return redirect()->route('posts.index');
}

The popup is queued into the session and rendered by the directive on the next full page render. That's the whole mental model: queue server-side, drain client-side.

Implementation Patterns

Fluent options instead of arrays. Every method returns a fluent builder, so you rarely touch raw option arrays:

swal()
    ->success('Invoice sent')
    ->footer('Ref #'.$invoice->id)
    ->timer(4000)
    ->position('bottom-end');

Available knobs: timer, position, confirmButton, cancelButton, footer, theme, width, plus the escape hatches option() (single key) and raw() (full options array).

Toasts for non-blocking feedback. Configure toast defaults once in the config, then:

swal()->toast('Draft autosaved');

Multiple popups per request. Call the helper repeatedly — they're queued in call order and shown one after another. Great for "Saved" → "Email queued" → "Webhook failed" in one import action, without a wall of text in one dialog. If you're firing more than two, reconsider — the user has to dismiss each one.

Popups survive redirect chains. Because they live in the session, a multi-step flow (validate → redirect → redirect) still shows the original message. Useful for onboarding wizards and payment callbacks; just remember alerts queued on a request that never renders the directive will sit in the session and reappear later.

Livewire components: use the trait, not the helper.

use Amjadiqbal\SweetAlert2\Livewire\SweetAlerts;

class EditPost extends Component
{
    use SweetAlerts;

    public function save(): void
    {
        $this->authorize('update', $this->post);
        $this->post->save();

        $this->swal('success', 'Saved', 'Changes are live.');
        $this->swalToast('Autosaved');
    }
}

Livewire requests don't do a full page render, so session-flashed alerts may never be drained. The trait pushes them to the browser over the component channel — that's the reliable path for in-place actions.

Confirm-before-destroy with a single attribute. No JS required:

<form method="POST" action="{{ route('posts.destroy', $post) }}" data-swal-confirm>
    @csrf @method('DELETE')
    <button type="submit">Delete</button>
</form>

<button wire:click="delete({{ $post->id }})" data-swal-confirm>Delete</button>

Works on <button>, <a> and <form>, and understands wire:click / wire:submit. Tune the copy and button labels in the confirm config block rather than repeating strings in markup.

Trusted markup is opt-in. Titles go over as titleText, and button labels and footers are HTML-escaped. For a branded message body, use html(); for full control over the SweetAlert2 options object, use raw(). Both bypass the escaping guarantee — never pass user input to either:

swal()->success('Order '.$order->number)
      ->html('<b>'.$order->number.'</b> is ready for pickup.');
// ^ $order->number must be trusted or pre-escaped

Hook the browser event. The package emits a sweetalert2 event; listen for analytics, logging or to chain your own client-side behaviour:

window.addEventListener('sweetalert2', (e) => {
    window.dataLayer?.push({ event: 'swal_shown', icon: e.detail?.icon ?? 'unknown' });
});

Testing. Assert the session queue rather than the DOM:

$this->post(route('posts.store'), $data)
    ->assertSessionHas('laravel-sweetalert2.alerts');

Gotchas and Tips

  • Missing directive = silent nothing. If popups "don't show", 95% of the time the layout is missing @sweetalert2 or <x-sweetalert2 />, or the flash happened on a layout that overrides the main one (auth pages, print views, PDF templates, error pages). Add it to every top-level layout.
  • SweetAlert2 comes from jsDelivr, not your bundle. That's a hard dependency on CDN reachability and on your CSP allowing cdn.jsdelivr.net. In air-gapped, intranet or strict-CSP environments you'll need to self-host: replace the directive with your own copy of SweetAlert2 and keep the config/runtime contract. SRI is pinned to 11.26.25 — pinning means security, but also that a browser with a stale cached bundle is fine while a tampered/404'd CDN is a hard failure.
  • CSP nonce must be set before the directive renders. The package reads Vite's CSP nonce and puts it on every script tag, including the runtime. If you call Vite::useCspNonce() late or use a non-Vite nonce source, the browser blocks the scripts and you get no popup and a CSP violation in the console. Check the console first when things are silently dead.
  • wire:navigate and data-navigate-once. The script tags are marked so Livewire's SPA navigation doesn't re-execute them. That's correct — but it means alerts queued during a wire:navigate page change rely on the runtime being alive from the first load. If you've swapped layouts between pages or removed the directive from one page, the queue silently backs up. Prefer the SweetAlerts trait inside Livewire components.
  • Titles are plain text by design. Passing '<b>Saved</b>' shows literal tags. That's the security feature, not a bug — reach for html() deliberately, and only with strings you constructed.
  • html() and raw() are the injection surface. Any value that touches them must be e()-escaped or hardcoded. Code review rule: if the argument contains $request, ->input(, ->name, or a model attribute the user can edit, it needs escaping first.
  • New session key. Alerts live under laravel-sweetalert2.alerts and the container binding is sweetalert2. Old snippets referencing alerts, session('alert') or the alert() helper won't work — the global helper is swal(). Worth a grep when migrating from tutorials written against the older/never-published package.
  • icon, not type. SweetAlert2 11.x renamed the option. If you're hand-rolling options through option() or raw(), type is silently ignored.
  • Version floor is steep. PHP 8.3+ and Laravel 12/13 only. On Laravel 10/11 this simply won't install — don't plan a partial rollout across a mixed-version fleet.
  • The swal() helper is global. It's a short, unnamespaced function name; if you already define one (or another package does), you'll get a fatal redeclare. Prefer the SweetAlert2 facade in libraries and packages to keep the global namespace clean.
  • Double-submit on confirm dialogs. The intercepted action runs after the user confirms. On slow requests, users click twice — disable the trigger or guard the handler server-side (idempotency key, wasRecentlyCreated check) rather than trusting the dialog as a rate limiter.
  • php artisan about is your version oracle. With a CDN-pinned frontend and a Composer-pinned backend, "which version is actually deployed" comes up in every bug report. That section answers it without shelling into the box.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource