@planningcenter/sweetest-alert
v1.7.0
Published
The sweetest alert ever
Keywords
Readme
Sweetest Alert
A lightweight, React alert/modal dialog component that replaces SweetAlert2 with a custom implementation using native HTML dialog elements.
Installation
yarn add @planningcenter/sweetest-alertIn your product’s main CSS file (ex. app/assets/stylesheets/application.css) add the required CSS imports:
@import "@planningcenter/tapestry/dist/index.css";
@import "@planningcenter/sweetest-alert/style.css";Peer Dependencies
This package requires the following peer dependencies:
react^18.3.1react-dom^18.3.1@planningcenter/tapestry^2.10.1 || ^3.0.0@planningcenter/icons^15.29.1
Usage
Basic Example
import { SweetestAlert } from "@planningcenter/sweetest-alert"
// Simple notification
SweetestAlert({
title: "Warning!",
content: "Watch out, he’s coming to get you!",
})Confirmation Dialog
SweetestAlert({
type: "danger",
title: "Delete Item",
content: "Are you sure you want to delete this item?",
onConfirm: () => console.log("Confirmed"),
onCancel: () => console.log("Cancelled"),
})Promise-based Usage
SweetestAlert also returns a promise that resolves to { isConfirmed, isDismissed }, so you can use .then()/await instead of (or alongside) onConfirm/onCancel:
const { isConfirmed } = await SweetestAlert({
type: "danger",
title: "Delete Item",
content: "Are you sure you want to delete this item?",
})
if (isConfirmed) {
deleteItem()
}Or chain .then() when you can’t (or don’t want to) use await:
SweetestAlert({
title: "Discard changes?",
content: "You have unsaved changes that will be lost.",
confirmButton: "Discard",
}).then(({ isConfirmed }) => {
if (isConfirmed) {
discardChanges()
}
})isDismissed is handy when you want to react to a cancel or Escape too, not just a confirm:
const { isConfirmed, isDismissed } = await SweetestAlert({
title: "Leave without saving?",
content: "Your draft will be lost if you leave now.",
})
if (isConfirmed) {
navigateAway()
} else if (isDismissed) {
trackEvent("leave_prompt_dismissed")
}Alert Types
The component supports five visual types:
// Info alert
SweetestAlert({
type: "info",
title: "Information",
content: "This is an informational message.",
})
// Success alert
SweetestAlert({
type: "success",
title: "Success!",
content: "Operation completed successfully.",
})
// Warning alert (default)
SweetestAlert({
type: "warning",
title: "Warning",
content: "Please proceed with caution.",
})
// Error alert
SweetestAlert({
type: "error",
title: "Error",
content: "Something went wrong.",
})
// Danger alert (for destructive actions)
SweetestAlert({
type: "danger",
title: "Delete Account",
content: "This action cannot be undone.",
confirmButton: "Delete",
})Custom Content
You can pass React components as content for rich formatting:
SweetestAlert({
title: "Custom Content",
content: (
<>
<p>You can include any React elements:</p>
<ul>
<li>Lists</li>
<li>Links</li>
<li>Formatted text</li>
</ul>
</>
),
})API
Parameters
| Parameter | Description |
| --------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| title | Required. The main heading text displayed at the top of the modal. |
| content | Required. The body content. Accepts plain text or React components (string \| React.ReactNode). |
| type | The visual type of alert (info, success, error, danger, warning), affects icon and styling. Defaults to "warning". |
| onConfirm | Callback executed when confirm button is clicked. |
| onCancel | Callback executed when cancel button is clicked. |
| confirmButton | Custom text for the confirm button. Defaults to "Okay". |
| hideCancel | When true, hides the cancel button for simple notifications. Defaults to false. |
Return Value
SweetestAlert returns a promise that resolves to { isConfirmed, isDismissed } when the dialog is closed (via confirm, cancel, or Escape), plus:
| Property | Description |
| --------- | ----------------------------------------------------------------------------------------------- |
| show | Re-opens the dialog (calls the native showModal()). |
| close | Closes the dialog (calls the native close()), resolving the promise with isDismissed: true. |
| cleanup | Unmounts the React root and removes the dialog from the DOM immediately. |
Development
Running the Demo
To run the interactive demo locally:
# Install dependencies
yarn install
# Start the development server
yarn devThen open your browser to http://localhost:3000. The demo showcases all alert types and features with interactive buttons.
Running Tests
The project uses Vitest for testing:
# Run tests once
yarn test
# Run tests in watch mode
yarn test --watchLinting
# Lint JavaScript/TypeScript files
yarn lint:js
# Lint CSS files
yarn lint:cssLicense
MIT
