A `Modal` pre-wired with a message and confirm/cancel actions, for "are you sure?" moments such as confirming a delete.
registry/behivetech/molecules/confirm-dialog at v0.2.9, snapshotted 2026-11-10
confirm-dialog.tsx
1import { type ReactNode } from "react";2import { getClassName } from "@bht-component-registry/class-names";3import { Modal } from "@behivetech/atoms.modal";4import { Button } from "@behivetech/atoms.button";5import styles from "./confirm-dialog.module.scss";67export interface ConfirmDialogProps {8 /** Whether the dialog is open */9 open: boolean;10 /** Called when the dialog should close (cancel, confirm, backdrop click, Escape) */11 onOpenChange: (open: boolean) => void;12 /** Dialog title */13 title: string;14 /** Confirmation message/body content */15 message: ReactNode;16 /** Confirm button label; defaults to "Confirm" */17 confirmLabel?: string;18 /** Cancel button label; defaults to "Cancel" */19 cancelLabel?: string;20 /** Called when the confirm button is clicked, before the dialog closes */21 onConfirm: () => void;22 /** Renders the confirm button as a destructive action; defaults to "default" */23 variant?: "default" | "danger";24}2526/**27 * A `Modal` pre-wired with a message and confirm/cancel actions, for "are you28 * sure?" moments — e.g. confirming a delete.29 */30export const ConfirmDialog = ({31 open,32 onOpenChange,33 title,34 message,35 confirmLabel = "Confirm",36 cancelLabel = "Cancel",37 onConfirm,38 variant = "default",39}: ConfirmDialogProps) => {40 const [, getChildClass] = getClassName({41 rootClass: "BHT__ConfirmDialog",42 styles,43 });4445 if (!open) return null;4647 return (48 <Modal title={title} onClose={() => onOpenChange(false)}>49 <p className={getChildClass("message")}>{message}</p>50 <div className={getChildClass("actions")}>51 <Button variant="ghost" onClick={() => onOpenChange(false)}>52 {cancelLabel}53 </Button>54 <Button55 variant={variant === "danger" ? "danger" : "primary"}56 onClick={() => {57 onConfirm();58 onOpenChange(false);59 }}60 >61 {confirmLabel}62 </Button>63 </div>64 </Modal>65 );66};
confirm-dialog.module.scss
1// Content of a Material Design 3 basic dialog; the dialog itself is Modal.23.BHT__ConfirmDialog {4 &__message {5 font-family: var(--md-sys-typescale-body-medium-font, var(--font-body));6 font-size: var(--md-sys-typescale-body-medium-size, 0.875rem);7 font-weight: var(--md-sys-typescale-body-medium-weight, 400);8 line-height: var(--md-sys-typescale-body-medium-line-height, 1.25rem);9 letter-spacing: var(--md-sys-typescale-body-medium-tracking, 0.0179em);10 color: var(--md-sys-color-on-surface-variant, var(--color-text-muted));11 margin: 0 0 var(--spacing-5, 1.25rem);12 }1314 &__actions {15 // Modal's panel is `surface-container-high`, where Button's default ghost16 // label (`primary`) is 4.02:1 in the-behive's Dark tokens (8.43:1 in the17 // defaults). `secondary` is 12.87:1 Dark and 5.40:1 Light there, so Cancel stays above the 4.5:1 small-text rule.18 --button-label-color: var(--md-sys-color-secondary);1920 display: flex;21 justify-content: flex-end;22 gap: var(--spacing-3, 0.75rem);23 }24}
index.ts
1export { ConfirmDialog } from "./confirm-dialog.js";2export type { ConfirmDialogProps } from "./confirm-dialog.js";
confirm-dialog.example.tsx
1import { useState } from "react";2import { ConfirmDialog } from "./confirm-dialog.js";34export const BasicConfirmDialog = () => {5 const [open, setOpen] = useState(false);67 return (8 <>9 <button type="button" onClick={() => setOpen(true)}>10 Delete page11 </button>12 <ConfirmDialog13 open={open}14 onOpenChange={setOpen}15 title="Delete page"16 message='Are you sure you want to delete "About Us"? This cannot be undone.'17 confirmLabel="Delete"18 variant="danger"19 onConfirm={() => console.log("confirmed delete")}20 />21 </>22 );23};