Confirmation dialog
'use client';
import { Button, Dialog, Stack, Text } from '@helixui/core';
export interface ConfirmDialogProps { isOpen: boolean; onOpenChange: (open: boolean) => void; title: string; description?: string; confirmLabel?: string; cancelLabel?: string; /** When true, the confirm button uses the danger tone. */ destructive?: boolean; onConfirm: () => Promise<void> | void;}
export function ConfirmDialog({ isOpen, onOpenChange, title, description, confirmLabel = 'Confirm', cancelLabel = 'Cancel', destructive = false, onConfirm,}: ConfirmDialogProps) { const handleConfirm = async () => { await onConfirm(); onOpenChange(false); };
return ( <Dialog isOpen={isOpen} onOpenChange={onOpenChange} aria-labelledby="confirm-title"> <Stack gap={4} style={{ padding: 'var(--helixui-space-5)', maxWidth: 420 }}> <Stack gap={1}> <Text id="confirm-title" size="lg" weight="semibold">{title}</Text> {description ? <Text size="sm" tone="muted">{description}</Text> : null} </Stack> <Stack direction="row" justify="end" gap={2}> <Button variant="ghost" tone="neutral" onClick={() => onOpenChange(false)}>{cancelLabel}</Button> <Button tone={destructive ? 'danger' : 'brand'} onClick={handleConfirm}>{confirmLabel}</Button> </Stack> </Stack> </Dialog> );}Usage
const [open, setOpen] = useState(false);
<> <Button tone="danger" onClick={() => setOpen(true)}>Delete project</Button> <ConfirmDialog isOpen={open} onOpenChange={setOpen} title="Delete this project?" description="This permanently removes the project, every file, and every link to it. This cannot be undone." confirmLabel="Delete" destructive onConfirm={() => deleteProject(id)} /></>The dialog traps focus, restores focus to the trigger on close, and
closes on Escape — those are Dialog defaults, not block-specific.