- Components
Alert dialog
A confirmation that cannot be dismissed by accident. Built on Dialog.
npx shadcn add @klarhimmel/alert-dialog @klarhimmel/buttonWhen to use
Use for
A decision with consequences that must not be taken by accident: delete, send, publish.
Not for
Information. Use Banner. A task with fields. Use Dialog.
Pairs with
Button, a short sentence.
Preview
Nothing deleted yet.
alert-dialog.tsx
import { Theme } from '@/components/klarhimmel/theme/style';
import { AlertDialog } from '@/components/klarhimmel/ui/alert-dialog';
import { Button } from '@/components/klarhimmel/ui/button';
export default function Example() {
return (
<Theme theme="brand">
<AlertDialog
destructive
trigger={<Button variant="secondary">Delete room</Button>}
title="Delete the Garden room?"
description="Its bookings are cancelled. This cannot be undone."
confirmLabel="Delete room"
onConfirm={() => console.log('deleted')}
/>
</Theme>
);
}Install
Import
import { AlertDialog } from '@/components/klarhimmel/ui/alert-dialog';- Lands in
- components/klarhimmel/ui/alert-dialog.tsx, plus cn() and the theme item if they are missing. Import theme.css after Tailwind.
- Render in
- Render it inside <Theme>, once near the root of your app. Tokens and fonts are scoped to it, so outside it the component is unstyled.
- Limit
- Overlays render into the Theme root with position: fixed. A transform on an ancestor re-parents fixed (a dialog centres in the wrapper) and overflow: hidden clips menus. Render <Theme> at the app root, outside any transformed wrapper.
Examples
Confirm
Draft saved, not sent.
import { useState } from 'react'; import { AlertDialog } from '@/components/klarhimmel/ui/alert-dialog'; import { Button } from '@/components/klarhimmel/ui/button'; export default function AlertDialogConfirm() { const [sent, setSent] = useState(false); return ( <div className="flex min-h-28 flex-col items-center gap-3"> <AlertDialog trigger={<Button>Send to 212 guests</Button>} title="Send the newsletter now?" description="It goes to every guest who agreed to hear from us. A sent email cannot be recalled." confirmLabel="Send newsletter" cancelLabel="Not yet" onConfirm={() => setSent(true)} /> <p role="status" className="text-kh-small text-kh-muted">{sent ? 'Sent.' : 'Draft saved, not sent.'}</p> </div> ); }Controlled
Nothing happened yet.
import { useState } from 'react'; import { AlertDialog } from '@/components/klarhimmel/ui/alert-dialog'; import { Button } from '@/components/klarhimmel/ui/button'; export default function AlertDialogControlled() { const [open, setOpen] = useState(false); const [log, setLog] = useState('Nothing happened yet.'); return ( <div className="flex min-h-28 flex-col items-center gap-3"> <Button variant="secondary" onClick={() => setOpen(true)}>Discard the draft</Button> <AlertDialog open={open} onOpenChange={(o) => { setOpen(o); if (!o) setLog((l) => (l === 'Draft discarded.' ? l : 'Kept the draft.')); }} title="Discard this draft?" description="Your changes to the room description are lost." confirmLabel="Discard draft" cancelLabel="Keep editing" onConfirm={() => setLog('Draft discarded.')} /> <p role="status" className="text-kh-small text-kh-muted">{log}</p> </div> ); }
API reference
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | - | Required. The question, written as one. |
description | string | - | Required. What happens if they say yes. |
confirmLabel | string | - | Required. Name the action ("Delete room"), never "OK". |
cancelLabel | string | 'Cancel' | The label of the safe button. |
onConfirm | () => void | - | Required. Runs when confirmed; the dialog closes after it. |
destructive | boolean | false | Styles the confirm button in the danger colour. |
trigger / open / onOpenChange | ReactNode / boolean | - | Same as Dialog. |
Accessibility
| Key | Does |
|---|---|
Tab / Shift+Tab | Cycles inside the dialog |
Escape | Cancels and returns focus to the trigger |
Enter / Space | Activates the focused button |
A click outside does not close it. Write the confirm label as the action, not "OK".
Accessibility