Alert dialog
Free · MITReact Native · ExpoA centered alert that springs in from slightly larger; touch an action and slide across the others with a tick per action, tap outside and it nudges, and async actions keep it open with a spinner until they settle.
Installation
$ npx shadcn@latest add https://goodui.dev/native/r/alert-dialog.jsonThen run npx expo install --fix so react-native-gesture-handler, react-native-reanimated match your Expo SDK. Files land in components/goodui-native/alert-dialog.
- Wrap the app in GestureHandlerRootView and ThemeProvider (the alert renders in its overlay layer).
Usage
import { AlertDialog } from "@/components/goodui-native/alert-dialog/alert-dialog";
export function CancelPlan({ open, onOpenChange }: { open: boolean; onOpenChange: (open: boolean) => void }) {
return (
<AlertDialog
open={open}
onOpenChange={onOpenChange}
tone="warning"
title="Cancel your Pro plan?"
message="You keep Pro features until Dec 1."
actions={[
{ label: "Keep Pro", style: "cancel" },
{ label: "Cancel plan", style: "destructive", onPress: () => api.cancelPlan() },
]}
/>
);
}When to use
- A decision the person must make before continuing: sign out everywhere, cancel a plan, leave without saving.
- Asking for one short value, such as a new name.
- A confirmation whose request can fail: return the promise and the alert shows pending and error itself.
- Deleting items: confirm in place with hold-to-confirm or offer Undo through toast.
- Several unrelated choices: use action-sheet.
- Telling someone an action worked: use the button's own success state or a toast.
- Forms with more than one field: use bottom-sheet.
Examples
With a text field
<AlertDialog
open={open}
onOpenChange={setOpen}
title="Rename workout"
input={{ defaultValue: workout.name, placeholder: "Workout name" }}
errorLabel="Give the workout a name."
actions={[
{ label: "Cancel", style: "cancel" },
{ label: "Save", onPress: (name) => (name.trim() ? api.rename(workout.id, name) : Promise.reject()) },
]}
/>Filled buttons, three actions stack
<AlertDialog
open={open}
onOpenChange={setOpen}
variant="filled"
title="Save changes to “Q3 report”?"
actions={[
{ label: "Save", onPress: save },
{ label: "Do not save", style: "destructive" },
{ label: "Cancel", style: "cancel" },
]}
/>API reference
| Prop | Type | Default |
|---|---|---|
| open* Whether the alert is shown. Closing animates out before it unmounts. | boolean | — |
| onOpenChange* Called with false after an action runs, or when the alert is dismissed. | (open: boolean) => void | — |
| title* One short question or statement. | string | — |
| message What happens and why, in one or two sentences. | string | — |
| actions Default: a single "OK". Two actions sit side by side; three or more stack. | AlertAction[] | — |
| actionsLayout `auto` puts two short actions side by side and stacks everything else. | "auto" | "row" | "stacked" | — |
| variant `plain` is the platform alert with hairline-separated text actions; `filled` uses rounded buttons. | "plain" | "filled" | — |
| tone Adds an icon badge above the title for a status. | "default" | "danger" | "warning" | "success" | — |
| input Adds a text field, such as a name or a password. | AlertInput | — |
| dismissible Allow closing by tapping outside or pressing back. Default `false`: an alert needs an answer, and a tap outside nudges it. | boolean | — |
| errorLabel Shown when an action's promise rejects. Same as `labels.error`. | string | — |
| haptic Haptics on commit and on async results. Default `true`. | boolean | — |
| labels Overrides for the built-in strings; a GooduiLocaleProvider pack sets them app-wide. | Partial<AlertDialogLabels> | — |
| testID Identifier for end-to-end tests. | string | — |
Motion and haptics
- Enter: scales from 1.1 to 1 on the bouncy spring while it fades in; exit fades and shrinks to 0.96.
- Actions follow the finger: the highlight moves to whichever action is under it, and releasing outside every action chooses nothing.
- Tap outside a non-dismissible alert: it nudges to 1.035 and springs back on the bouncy spring.
- Async failure: the card shakes and the error appears; filled buttons also scale to 0.97 under the finger.
- With a text field the card rises by half the keyboard height so it stays centered in the free space (native).
- Reduced motion: no scale-in, nudge, shake or button scale; the alert fades in and out.
- Haptic: tap when an action is chosen
- Haptic: select each time the finger slides onto another action
- Haptic: success when an action's promise resolves, error when it rejects
- Highlight and hit testing run on the UI thread; the alert mounts only while open or closing.
Accessibility
- The card has accessibilityRole alert and is modal; the title and message are announced when it opens.
- Each action is a button with busy and disabled states; double tap activates it. On the web actions are focusable buttons (Enter or Space).
- A failed action announces errorLabel and shows it under the message.
- Android back runs the cancel action when there is one (or closes a dismissible alert); otherwise it nudges.
Notes for AI
- Label actions with verbs; mark the safe way out with style 'cancel' and the risky one with 'destructive'.
- Return a promise from onPress to keep the alert open with a spinner; it closes on success and shakes with errorLabel on failure. Do not add your own loading state.
- onPress receives the text field's value when input is set.
- Alerts are not dismissible by default; pass dismissible for purely informational alerts.
- Two short actions (14 characters or fewer) sit side by side; set actionsLayout to force a row or a stack.
Related
An iOS-style list of choices that springs up from the bottom edge in grouped cards; it follows the finger to be dragged away, and pulling it up stretches the gap between the cards before they spring back together.
A sheet that rests at detents, follows the finger 1:1, settles with velocity and hands drags off to its scroll view.
Confirms an irreversible action by holding: ink fills from the leading edge, the label inverts where the ink passes, and haptics tick at every quarter.
Background confirmations that stack at the top, fan out on tap, swipe away up or sideways, and pause their timers while touched.