nori-ui

AlertDialog

Confirmation modal that forces a user response — no escape, no click-outside.

4.7 kBgzipped

At a glance

  • Compose: AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogTitle, AlertDialogDescription, AlertDialogCancel, AlertDialogAction, AlertDialogFooter. Triggers / Cancel / Action use asChild by default — wrap any element and it becomes the activator.
  • Forces a response: backdrop click does not close, Escape does not close. The user MUST press Cancel or Action.
  • Initial focus lands on Cancel — the least destructive default — so a stray Enter keypress can't fire the destructive action.
  • Accessibility: role="alertdialog" with aria-modal, aria-labelledby on the title, aria-describedby on the description.
  • Cross-platform: uses RN <Modal> as the visibility primitive. Web layers on focus trap, scroll lock, focus restore. Subtle scale-in animation (150ms) honors prefers-reduced-motion.

When to use AlertDialog vs Dialog

Use AlertDialog for destructive or otherwise irreversible confirmations — "Delete project?", "Sign out everyone?", "Discard unsaved changes?". The user has to make an explicit choice, which matches the weight of the action.

Use Dialog for everything else — forms, info, settings, embedded flows. Dialog allows Escape and click-outside to dismiss, which is the expected affordance for forgettable, low-stakes interactions.

Choosing the wrong one is a real accessibility / UX bug: if Dialog gates a destructive action, users will lose work by tapping outside; if AlertDialog gates a form, users will feel trapped.

Preview

Direction:
Locale:

Open state — open, defaultOpen, onOpenChange

open (controlled) + onOpenChange is the parent-driven shape; pass defaultOpen for uncontrolled mode. Mixing the two prefers controlled and ignores defaultOpen. Trigger / Cancel / Action subcomponents already flip the state for you, so most call sites don't need either.

const [open, setOpen] = useState(false);
<AlertDialog open={open} onOpenChange={setOpen}>...</AlertDialog>

Anatomy

SubcomponentRole
AlertDialogRoot — owns open state (controlled or uncontrolled).
AlertDialogTriggerElement that opens the dialog. asChild by default.
AlertDialogContentThe visible surface. Renders only while open. Backdrop click and Escape do nothing.
AlertDialogTitleHeading. Wires aria-labelledby.
AlertDialogDescriptionBody description. Wires aria-describedby.
AlertDialogCancelDismiss action. Receives initial focus. Forwards onPress, then closes.
AlertDialogActionConfirming / destructive action. Forwards onPress, then closes.
AlertDialogFooterRight-aligned row for the Cancel / Action buttons.

Usage

import {
    AlertDialog,
    Button,
} from '@nori-ui/core';
 
export function DeleteProjectButton({ onDelete }: { onDelete: () => void }) {
    return (
        <AlertDialog>
            <AlertDialog.Trigger>
                <Button variant="destructive">Delete project</Button>
            </AlertDialog.Trigger>
            <AlertDialog.Content>
                <AlertDialog.Title>Delete this project?</AlertDialog.Title>
                <AlertDialog.Description>
                    This permanently removes the project and every record attached to it. This cannot be undone.
                </AlertDialog.Description>
                <AlertDialog.Footer>
                    <AlertDialog.Cancel>
                        <Button variant="secondary">Cancel</Button>
                    </AlertDialog.Cancel>
                    <AlertDialog.Action onPress={onDelete}>
                        <Button variant="destructive">Delete project</Button>
                    </AlertDialog.Action>
                </AlertDialog.Footer>
            </AlertDialog.Content>
        </AlertDialog>
    );
}

Props

AlertDialog

PropTypeDefaultDescription
defaultOpenbooleanfalseUncontrolled initial open state. @defaultValue false
onOpenChange(open: boolean) => voidFires with the new open state.
openbooleanControlled open state.

AlertDialogTrigger

PropTypeDefaultDescription
asChildbooleantrueRender the child as the trigger (Slot pattern). Default true.
classNamestring
testIDstring

AlertDialogContent

PropTypeDefaultDescription
classNamestring
testIDstring

AlertDialogCancel

PropTypeDefaultDescription
asChildbooleantrueRender the child as the cancel button (Slot pattern). Default true.
classNamestring
onPress(event?: unknown) => voidForwarded to the wrapped child / fallback Pressable. Fires before close.
testIDstring

AlertDialogAction

PropTypeDefaultDescription
asChildbooleantrueRender the child as the action (Slot pattern). Default true.
classNamestring
onPress(event?: unknown) => voidForwarded to the wrapped child / fallback Pressable. Fires before close.
testIDstring

On this page

Preview theme