build69
build69  /  Components  /  Overlays  /  Popconfirm

Popconfirm

v1.0.18Updated 19 Oct 2026

Inline confirmation popover for destructive or consequential actions. Wraps any trigger; on open shows a tone-aware icon, title, optional description, and Cancel + Confirm buttons. Async onConfirm shows a loading spinner

Preview

Live · 10 stories
DefaultOpen ↗
▸Why this is recommendedconfirmdestructivepopoverinline-dialog+3

The default, out-of-the-box Popconfirm.

Recommended for+14
  • ✓Delete buttons in tables and lists
  • ✓Void / cancel / archive actions
  • ✓Any one-click action that needs a lightweight second look without a full Dialog
Tags+6
confirmdestructivepopoverinline-dialogasyncradixdefault
Features+4
  • Tone-aware icon + accent via shared tone recipes (danger default)
  • Sync or async onConfirm with loading state on the confirm button
  • Stays open and shows the rejection message on async error
  • Focus moves to Cancel on open; Escape cancels; dismissal blocked mid-flight
  • Controlled and uncontrolled open state
  • side / align / sideOffset placement
  • disabled prop suppresses opening entirely
  • closeOnOutsideClick={false} makes an outside click no answer at all — neither confirm nor cancel — so a misplaced click cannot silently dismiss the question (fb_8ca9c11a)
  • Custom icon override (or icon={null} to hide)
  • i18n: labels prop overrides the Confirm/Cancel fallbacks and the async-error fallback message; merged over DEFAULT_POPCONFIRM_LABELS (confirmLabel/cancelLabel props win)
Not recommended for−2
  • ✕Multi-field input before confirming (use Dialog or Popover form)
  • ✕Legally significant confirmations that must interrupt (use AlertDialog/Dialog)

Install

Ask your agent, or call the MCP tool directly. The resolved bundle is written into your project.

get_registry_item({ name: "Popconfirm" })

Usage

import { Popconfirm } from '@/components/overlays/popconfirm';

<Popconfirm
  title="Delete this invoice?"
  description="This action cannot be undone."
  onConfirm={() => api.deleteInvoice(id)}
>
  <Button tone="danger" emphasis="soft">Delete</Button>
</Popconfirm>

Tick variants in the left menu — each adds a tab with that variant’s real story source, the same code the preview above renders.

Props

PropTypeRequired
children

The trigger the popconfirm wraps, rendered through Radix `asChild` — so pass exactly ONE element that forwards a ref and spreads props, e.g. a Button. There is no trigger prop: the element you wrap IS the trigger, and a second click on it closes the popconfirm without recording an answer

React.ReactNodeyes
title

Short question, e.g. "Delete this invoice?"

ReactNodeyes
description

Supporting copy explaining the consequence

ReactNode—
tone

Semantic tone; picks icon + accent (default danger)

'neutral' | 'primary' | 'success' | 'warning' | 'danger' | 'info'—
onConfirm

Sync closes immediately; async shows loading, closes on resolve, shows error on reject

() => void | Promise<void>—
onCancel

Called on the cancel button, Escape, or an outside click — the last of those only while closeOnOutsideClick is true

() => void—
confirmLabel

Confirm button label (default "Confirm")

ReactNode—
cancelLabel

Cancel button label (default "Cancel")

ReactNode—
disabled

Prevents opening entirely

boolean—
side

Preferred side (default top)

'top' | 'right' | 'bottom' | 'left'—
align

Alignment against the trigger (default center)

'start' | 'center' | 'end'—
sideOffset

Distance from the trigger in px (default 6)

number—
icon

Replace the tone-derived icon. Pass `null` to drop the icon and its circle entirely; leave it undefined to keep the icon the tone chose

React.ReactNode—
open

Controlled open state (defaultOpen for uncontrolled)

boolean—
defaultOpen

Initial open state for uncontrolled usage; ignored once `open` is provided

boolean—
onOpenChange

Fires whenever the open state changes, controlled or not. It is the open/closed signal, not the answer — read `onConfirm` / `onCancel` for that. It is NOT called for a request the component refuses: opening while `disabled`, or any dismissal while an async confirm is still in flight

(open: boolean) => void—
closeOnOutsideClick

Whether a click outside cancels (default true — the behaviour it has always had). Set false and an outside click is no answer at all: onCancel does not fire and the question stays on screen. Escape and the Cancel button are unaffected (fb_8ca9c11a)

boolean—
labels

Override the built-in strings (i18n): Confirm/Cancel fallbacks and the async-error fallback message. Merged over DEFAULT_POPCONFIRM_LABELS

Partial<PopconfirmLabels>—

Every tonal component shares the same tone × emphasis API, so the pair looks identical across Button, Badge, Alert and more.

Related