pentiminax/ux-sweet-alert
A Symfony UX integration for SweetAlert2 that lets you trigger polished alerts, confirmations, and toasts from PHP or Twig. It provides simple helpers and Stimulus-powered behavior so you can add rich, interactive dialogs without writing custom JavaScript.
Note first: despite the "Laravel/PHP package" framing, pentiminax/ux-sweet-alert is a Symfony UX bundle, not a Laravel package. There is no service provider or config/sweetalert.php — everything flows through Flex, Stimulus, and Twig. Plan accordingly.
Install (Symfony 6.4+/7.x, UX 3.0 as of v0.21):
composer require pentiminax/ux-sweet-alert
Then wire the front-end controller, which ships inside the package's assets/ directory and is registered through assets/controllers.json:
# AssetMapper
php bin/console importmap:install
php bin/console importmap:require sweetalert2 # if the recipe didn't do it
# or Webpack Encore
npm install && npm run dev
Where to look first:
vendor/pentiminax/ux-sweet-alert/README.md — the canonical option names; treat those as authoritative over anything below.vendor/pentiminax/ux-sweet-alert/assets/controllers/sweet-alert_controller.ts — as of v0.21 this is TypeScript, not JS. It is the real source of truth for which Stimulus values exist and what they map to in SweetAlert2's Swal.fire() options.vendor/pentiminax/ux-sweet-alert/src/ — the PHP side (service + Twig extension) if you want to render alerts from a controller rather than a template.First use case — flash message to toast:
The 80% case is: a controller action does its work, adds a flash, redirects, and the next page renders a toast. That's the flow to get working end-to-end before touching confirm dialogs. If you see the flash appear in Twig but no toast, the problem is almost always the Stimulus controller not being loaded (importmap/Encore build), not the bundle.
Version gate: v0.21.0 declares support for Symfony UX v3.0. If any other symfony/ux-* package in your app is still pinned to ^2, Composer will either conflict or leave you on v0.20.1. Check composer show 'symfony/ux-*' before upgrading.
Flash-driven toasts (the default pattern). Set the flash in the controller, render the alert element in your base layout so every page picks it up:
// src/Controller/OrderController.php
$this->addFlash('success', 'Order #1042 saved.');
return $this->redirectToRoute('order_index');
{# templates/base.html.twig #}
{% for type, messages in app.flashes %}
{% for message in messages %}
<div {{ stimulus_controller('sweet-alert', {
icon: type == 'success' ? 'success' : 'error',
title: message,
timer: 3000,
showConfirmButton: false,
}) }}></div>
{% endfor %}
{% endfor %}
The empty <div> is intentional — the controller is a pure behaviour hook; SweetAlert2 renders its own DOM.
Explicit modal from a template. For a one-off confirmation on a specific page, drive it with stimulus_controller values directly and skip the flash bag entirely. Reserve this for the few screens that need it; don't scatter modal config across templates — put defaults in one Twig partial and include it with overrides.
Confirm-before-destructive-action. Attach the controller to the form/button and intercept the submit, showing a modal whose confirm path re-submits. Keep the server-side authorisation intact — a client-side confirm is UX, not security. Never let the presence of a SweetAlert confirm replace a CSRF token or voter check.
Turbo/Fetch composition. Stimulus connect() fires on turbo:load, so flash-driven toasts work after Turbo navigations without extra wiring. For alerts triggered by a Turbo Stream response, render the controller element inside the stream partial — the newly inserted node connects and fires on its own. If you need to fire an alert from a stream without inserting markup, dispatch a custom event and have a persistent controller listen for it.
Multiple alerts on one page. Several controller elements each instantiate their own Swal.fire(). SweetAlert2 queues them, which is usually fine for two or three — but five flash messages becomes a modal conga line. Collapse to a single alert server-side (join messages, or keep only the highest-severity one) rather than relying on the client to throttle.
Testing. Assert the flash and the rendered data-controller attribute in functional tests ($client->followRedirect(); $this->assertSelectorExists('[data-controller="sweet-alert"]')). The actual dialog is untestable without a real browser — if the toast is business-critical, add one Panther/Playwright smoke test rather than trying to assert SweetAlert2's DOM from PHPUnit.
TypeScript from v0.21. The controller is now .ts. With Encore, add ts-loader (or switch to esbuild-loader) and a tsconfig.json, otherwise the build fails on the vendor controller with a parse error. With AssetMapper, ensure your Symfony version transpiles .ts in vendor/ paths — if it doesn't, you'll get a 404 or a MIME error on the controller module and the symptom is a silent "no toast on page load, console shows nothing obvious."
symfony/ux 3.0 support means the v2 line is dropped; the controller name, Stimulus values, and Twig usage are unchanged by the JS→TS refactor. Your templates should not need edits. Upgrade the whole symfony/ux-* family together.assets/controllers/. If you previously did (a common workaround pre-recipe), the v0.21 .ts rename means your stale .js copy silently shadows the new one and you get none of the fixes. Delete the local copy and use the package's.controllers.json overrides. To swap in your own controller, set the package entry to false and register yours under the same name — that's the cleanest extension point and it survives package upgrades. Decorating the PHP service is the right hook if you need to change what the server renders.Swal.fire() from your own script alongside the controller produces duplicated or dropped dialogs because both manipulate the same singleton. Pick one path per feature.<style> tags at runtime. Sites with a strict style-src will render an unstyled, broken-looking modal (or nothing). Add a nonce or allow 'unsafe-inline' for styles — this is the number one "it works locally, fails in prod" cause.turbo:before-cache.data-controller element actually in the DOM? (2) does the browser network tab show the controller module loading — 404/MIME error means asset pipeline; (3) console for Stimulus "Missing controller" warnings, which mean the module loaded but the identifier doesn't match; (4) only then suspect the SweetAlert2 options. Run php bin/console importmap:audit for AssetMapper projects.Swal.fire() are ignored by SweetAlert2 with no error. When a value has no effect, diff your key against the README before assuming the bundle is broken.0.x release following a major dependency bump; if you're not ready to move the whole UX stack, "pentiminax/ux-sweet-alert": "0.20.*" is a valid holding position.How can I help you explore Laravel packages today?