marcorombach/livewire-confirm-modal
A Livewire directive that shows a styled confirm modal instead of the browser's native confirm() dialog, so confirmations look consistent across browsers. Supports custom titles and descriptions via wire:confirm-modal, works with wire:click, and the view is publishable for your own Tailwind styling.
Build-vs-buy on a commodity interaction. Confirmation dialogs are rebuilt on nearly every project and are never a differentiator. This package converts a small component-and-styling backlog item into roughly a day of integration plus a design-system styling pass. That is the right trade when the alternative competes with committed roadmap work for the same sprint — and the wrong trade if we already intend to own a modal primitive within two quarters, in which case this is a stopgap and should be logged as one rather than absorbed silently into the codebase.
Destructive-action safety as a shippable increment. Every delete, revoke, cancel, or irreversible state change needs a guard rail. The wire:confirm-modal directive lets us add that guard rail per call site with no flag day, no migration, and no server-side change. This is the kind of work that tends to get bundled into a larger "hardening" epic and never scheduled; here it can be scoped as a bounded, per-surface rollout with a mechanical revert path.
Browser-consistency as a real product requirement. Native confirm() renders differently on every browser and OS, cannot be styled, and cannot carry translated body copy with any visual control. If confirmation copy is product-owned, localized, or brand-relevant, the native dialog is a visible quality gap in exactly the moment a user is about to do something irreversible. The package closes that gap cheaply.
Scoping a pilot rather than a sweep. The package's cost curve is breadth-of-adoption × probability-of-missing-a-layout — the component tag must be mounted in every layout where the directive fires, and omitting it fails silently (click swallowed, no modal, no error). That argues for converting a bounded set of high-value destructive actions in one or two layouts, measuring it, and broadening only if the manual QA surface stays coverable. This is a decision about rollout scope, and it is the most consequential one on the table.
Deferring accessibility spend, consciously. The README makes no ARIA, focus-trap, Escape-to-close, or focus-restore claims. For a modal that gates destructive actions, that gap becomes our liability at ship time, not the maintainer's. The PM decision is whether the pilot surfaces carry an accessibility or compliance obligation: if yes, fork-and-harden is in the critical path and the effort estimate roughly triples; if no, it is a logged follow-up with a named trigger.
Standardizing confirmation copy. The title|description attribute is a string DSL with no schema and no escaping story — a translated description containing a | silently corrupts the payload. Deciding early whether confirmation copy is product-owned and localized (and therefore must route through an internal wrapper that owns the API and escapes the delimiter) is a product decision, not an implementation detail. Made late, it means re-touching every call site.
Good fit when:
wire:click actions specifically — the documented contract — and those actions are destructive enough to matter but not regulated.<x-confirm-action> component so call sites never touch the vendor package directly.Look elsewhere or build in-house when:
wire:submit, lazy wire:model updates, wire:poll actions, or plain form posts. These are outside the documented contract and would need engineering verification before they appear in any demo or commitment — the answer changes the build-vs-buy math entirely.Continuity caveat that applies to every adoption decision: single maintainer, 3 stars, 0 dependents, a 0.2.x version line that is an explicit non-promise of API stability, and a changelog that reads as stabilizing rather than stable — small correctness fixes for parameter passing, Alpine coexistence, Tailwind 4 utilities, then Laravel 13 / Livewire 4 support. Current compatibility is confirmed; forward compatibility is a coin flip. Pin the version, and treat "upgrade Livewire/Tailwind" and "verify this package still works" as one ticket, not two.
To executives: We can close a real quality gap on destructive actions — the ugly, browser-inconsistent popup that appears right before a user deletes something — for roughly a day of engineering plus a styling pass, instead of a from-scratch component build that competes with committed roadmap work. The integration footprint is markup only: no database changes, no server-side state, no new infrastructure, and the exit cost is a mechanical revert. The honest framing of risk: this is an unproven single-maintainer package, so we should scope it to a bounded pilot on internal back-office surfaces, pin the version, and name an owner on day one. If confirmation dialogs are already on the design-system roadmap, this is a deliberate stopgap and we should say so out loud rather than let it quietly become permanent.
To engineering: Low effort with one deceptively expensive tail. Install and pin, add the vendor view path to the Tailwind content config, mount <x-livewire-confirm-modal/> in the relevant layouts, publish the view into our repo, and wrap it in an internal component that owns the title/description API and escapes the pipe delimiter so call sites never reference the vendor path. The two things that must be verified before we call it done are the ones that fail silently: layout mount coverage (a missing tag means the click is swallowed with no error and no console output — manual QA is the only detection) and styling against a production Tailwind build. Budget the accessibility work explicitly if any pilot surface has a compliance obligation, because there is no ARIA, focus-trap, or Escape handling in the shipped view and forking it makes it our maintenance burden. Ramp-up is under an hour for anyone who knows Livewire; the onboarding cost is three facts worth writing into the component guide — the mount prerequisite, the title|description delimiter convention, and "go through the wrapper, not the vendor tag."
The ask: Approve a scoped pilot on a bounded set of destructive actions in internal surfaces, with a named owner, a pinned version, and a revisit trigger tied to our next Livewire or Tailwind major upgrade.
How can I help you explore Laravel packages today?