Dan Marino Headshot

Dan Marino

UX Engineer • Trust & Safety

QR code linking to presentation

The Sweetest Alert

A <dialog> Migration Story

Sweet Alert Has Overstayed

The Browser’s Gift

Focus trapping

Built-in — no library or manual event management needed.

Keyboard support

Escape to close, tab order — all handled natively.

::backdrop

Native overlay is baked in — no extra DOM required.

Top-layer promotion

Dialogs always render above everything. No z-index battles!

Sweetest Alert

SweetestAlert({ title: "Archive group?", content: "Are you sure you want to archive this group?", confirmButton: "Archive", onConfirm: () => archiveGroup(), })

By the Numbers

Sweet Alert
~24 KB Over the wire (gzip)
1,378 Lines of CSS
Sweetest Alert
~3 KB Over the wire (gzip)
64 Lines of CSS

The Strategy

The temptation
  • Big rewrite
  • Migration plan doc
  • All or nothing
What we actually did
  • Inventory every instance
  • Proof of concept in a low-traffic area
  • Convert 2–3 at a time, growing in complexity
  • Expand features as each wave reveals needs

Packaging

Rails Support

Stimulus Controller
import { Controller } from "@hotwired/stimulus" import { SweetestAlert } from "@planningcenter/sweetest-alert" export default class extends Controller { open(event) { SweetestAlert({ content: this.contentValue, title: this.titleValue, onConfirm: () => this.element.closest("form").submit(), }) } }
ERB Usage
<%= button_to "Do thing", path, { method: :delete, data: data_for_sweetest_alert( title: "Hold on a second", content: "Yadda yadda…" ) } %>

AI as Dev Partner

Building

Used Claude Code to help build the component

Docs & demos

Generated docs, demos, and boilerplate with Claude

Migration

Used AI-assisted scripts to speed up migration across Accounts

Code review & tests

AI-assisted test scaffolding and review across conversions

The Payoff

Sweet Alert instances remaining in /accounts

yarn remove sweetalert2

Thanks!

@marino on Slack github.com/planningcenter/sweetest-alert