Skip to content

Introduction

Open source confirmation components for shadcn/ui: undo, hold to confirm, type to confirm and more. Built on Base UI.

When every action opens an "Are you sure?" dialog, people stop reading and confirm on reflex. The one dialog that matters gets the same click as the fifty before it.

SureUI has other ways to ask: undo, hold to confirm, type to confirm, a second click, or a dialog. Each component installs into your project from the @sureui registry, so the code is yours to change.

On the control itself

  • Confirm Button confirms on a click, a second click or a press and hold, with optional undo.
  • Confirm Menu Item brings the same gestures to dropdown and context menu items.
  • Confirm Switch moves right away and can be flipped back during the undo window.

When it needs more room

  • Type to Confirm unlocks only after the exact phrase is typed.
  • Confirm Dialog puts a confirmation in an alert dialog, with an awaitable useConfirm.
  • Confirm Popover anchors a one-line confirmation to its trigger.
  • Consequences lists what a confirmation will remove or change, with counts and names.

Undo after the fact

  • Undo Toast shows a toast with Undo and resolves once nobody undoes.
  • Undoable collapses a removed row in place to a label and an Undo button.

Moments with their own rules

  • Unsaved Changes asks before unsaved changes are lost, when leaving a page or closing a dialog.
  • Tool Approval approves or denies an AI SDK tool call with a gesture that matches its risk.

To build your own trigger, like a card or a keyboard shortcut, use the hook every component is built on: Confirmation Core.

Every component except Tool Approval takes the same onConfirm. Return a promise and the control stays pending until it settles. onCancel runs when someone backs out or presses Undo. Every control sets data-state, so you can style around it.

tsx
async function deleteProject() {  await api.projects.delete(id)}<ConfirmButton undo onConfirm={deleteProject}>Delete</ConfirmButton><ConfirmButton gesture="click-again" onConfirm={deleteProject}>Delete</ConfirmButton><ConfirmButton gesture="hold" onConfirm={deleteProject}>Delete</ConfirmButton><TypeToConfirm phrase="acme-prod" onConfirm={deleteProject} /><ConfirmDialog title="Delete acme-prod?" onConfirm={deleteProject}>  <Button>Delete</Button></ConfirmDialog>