Dashral Pro is on the wayGet 30% off at launch

Dashral

Alert Dialog

AlertDialog with motion: it grows out of its button, its icon pops in, a click outside shakes it because it needs an answer, and confirm can be a press-and-hold.

$ pnpm dlx shadcn@latest add https://dashral.com/r/motion-alert-dialog.json

Installation

$ pnpm dlx shadcn@latest add https://dashral.com/r/motion-alert-dialog.json

Adds components/dashral/motion/alert-dialog.tsx, the Alert Dialog it builds on (in components/dashral/), motion and the motion files every motion component shares. With the registry in your components.json:

$ pnpm dlx shadcn@latest add @dashral/motion-alert-dialog

Usage

The same as Alert Dialog, imported from components/dashral/motion/: swap the import and it moves.

example.tsx
import { AlertDialog } from "@/components/dashral/motion/alert-dialog"

<AlertDialog
  trigger={<Button color="destructive">Delete project</Button>}
  title="Delete this project?"
  color="destructive"
  confirmLabel="Delete"
  onConfirm={() => api.projects.delete(id)}
/>

Examples

Hold to delete

holdToConfirm: confirm is a press-and-hold. Click outside and the panel shakes.

Waiting for the server

Signing out… while the promise runs; the first try fails and the reason grows in, the second goes through with a toast.

Compared with Default

Default

Fades and zooms in from 95% in the middle of the screen; a click outside does nothing.

Motion

Grows out of its button and shrinks back into it; its icon pops in (a destructive one wiggles); a click outside shakes it; holdToConfirm makes confirm a press-and-hold.

How the two editions differ in general, and which to use where: Motion.

API reference

Every prop of Alert Dialog, and every attribute of the element it renders. What the Motion edition adds is marked Motion.

AlertDialog

Also takes every prop of Radix Alert Dialog(opens in a new tab).

PropTypeDefault
holdToConfirmboolean | number

Motion Confirm has to be pressed and held this long (true for 1.2s, or milliseconds), as Button's.

false
triggerReactElement

What opens it, e.g. a Delete button. Leave it out to open it with open / onOpenChange.

—
titleReactNode

Required: the question, which names the dialog.

—
descriptionReactNode

What happens if they go ahead.

—
childrenReactNode

More between the text and the buttons, e.g. a field to type a name.

—
iconReactNode

In a tinted circle beside the text.

—
color"primary" | "destructive"

The confirm button's (and the icon's) color; destructive for deleting.

"primary"
confirmLabel / cancelLabelReactNode

The buttons' labels (translated by default).

"Continue" / "Cancel"
onConfirm() => void | Promise<unknown>

Runs on confirm. A promise keeps the dialog open with the button showing it's working; it closes when the promise resolves, and stays if it rejects.

—
loadingTextReactNode

Beside the spinner while onConfirm's promise runs.

—
confirmDisabledboolean

Keeps confirm off, e.g. until a name is typed.

false
open / defaultOpen / onOpenChange

Controlled or initial state.

—
classNames{ title, description, footer }

Classes for each part.

—
classNamestring

The panel's classes.

—

Motion

  • It grows from 60% out of the button that opened it on a quick spring, and shrinks back toward it as it closes.
  • The icon pops in after it; a destructive icon gives a short wiggle.
  • A click outside doesn't close it, so the panel shakes sideways a few pixels: it needs an answer.
  • Confirm is the motion Button: it shows it's working while onConfirm's promise runs, and with holdToConfirm it fills while held.
  • With reduced motion it only fades and nothing shakes or wiggles.