react-confirm

Turn any React component into a callable, Promise-based confirmation dialog.

Library
npm
v0.5.0
277stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
59/100Fair
Development Activity60
Maintenance36
Community60
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
79/100Good
Architecture82
Code Quality88
Innovation62
Learning Curve85

react-confirm lets you call a confirmation dialog like window.confirm()await confirm({ message: '...' }) — while rendering your own fully custom React component underneath. There’s no built-in UI: you write the dialog markup and styling once, wrap it with confirmable(), and turn it into an awaitable function with createConfirmation(). The result resolves or rejects the surrounding Promise based on which button the user clicks, so callers can await a yes/no (or richer typed) answer without threading dialog-open state through props or a global store.

The library ships two mounting strategies. The default DOM-tree mounter creates its own React root and portal-mounts the dialog directly into document.body (or a node you specify), requiring no setup in your component tree. The context-aware variant (ContextAwareConfirmation) instead renders dialogs inside a <ConfirmationRoot /> you place in your own app tree, so dialogs inherit React Context — themes, i18n providers, auth state — that a portal mounted outside the tree would otherwise miss. A small controls module also lets code far from the call site externally proceed(), dismiss(), or cancel() a still-pending confirmation by reference to its Promise, useful for things like auto-dismissing a dialog on a timeout.

What You Get

  • createConfirmation() — wraps a confirmable component into a function that returns a Promise, resolving with whatever value the dialog calls proceed() with
  • confirmable() higher-order component that injects show, proceed, cancel, and dismiss into your dialog’s props
  • A context-aware mounting mode (ContextAwareConfirmation + <ConfirmationRoot />) so dialogs render inside your app tree and can read React Context (themes, providers, i18n)
  • External control functions — proceed, dismiss, cancel — to resolve or close a pending dialog from anywhere in the codebase by referencing its Promise
  • Full TypeScript inference: dialog prop types and the resolved response type both flow through to the generated confirm() function’s call signature

Common Use Cases

  • Replacing native window.confirm()/alert() calls with a themeable, on-brand dialog while keeping the same simple call-and-await usage
  • Delete/destructive-action confirmations in CRUD interfaces, where the calling code just needs a boolean answer
  • Multi-button or form-like confirmation dialogs that resolve with a typed object instead of a plain boolean
  • Auto-dismissing a still-open confirmation after a timeout using the external proceed/dismiss controls
  • Dialogs that must consume the surrounding app’s theme or auth context, via the context-aware mounting mode

Under The Hood

Architecture The library separates three concerns into distinct modules that compose rather than inherit: confirmable.tsx is a higher-order component that injects show/proceed/cancel/dismiss onto a caller-supplied dialog; createConfirmation.ts wraps a confirmable component into a function returning a Promise, wiring the dialog’s callbacks to that Promise’s resolve/reject; and a pluggable Mounter interface (mount/unmount) decides where the component actually renders. Two mounters implement that interface — mounter/domTree.tsx creates its own React root and portals into document.body, while mounter/reactTree.tsx keeps a live map of mounted components and re-renders through a <ConfirmationRoot /> placed inside the caller’s own tree, which is what lets context.ts’s ContextAwareConfirmation give dialogs access to surrounding React Context. A separate controls.ts module keeps a WeakMap-free registry keyed by Promise identity so code outside the dialog’s own render tree can force-resolve, reject, or dismiss a pending confirmation. Swapping the mounter is the one abstraction the whole system pivots on; changing it doesn’t touch confirmable or createConfirmation at all.

Tech Stack Written entirely in TypeScript (99% of the codebase) with zero runtime dependencies — react and react-dom (>=18.x) are declared only as peer dependencies. The build is a plain tsc -p tsconfig.build.json producing dist/index.js plus .d.ts declarations, no bundler or transpiler in the loop. Tests run under Jest 29 with jest-environment-jsdom, @testing-library/react, and ts-jest; regenerator-runtime is pulled in only to support async/await in the jsdom test environment. There’s no CI config visible beyond a .github/ directory, and publishing is a straightforward npm run clean && npm run build && npm test prepublish sequence.

Code Quality The test suite is substantial for the library’s size — over 2,000 lines across 11 files, split between behavioral tests (createConfirmation.test.tsx, confirmable.test.tsx, controls.test.ts, context.test.tsx, integration.test.tsx) and a dedicated __tests__/typescript/ directory of compile-time type-constraint and inference tests (type-constraints.test.ts, contextAwareTypeInference.test.tsx, compatibility.test.ts) — unusually rigorous for verifying that generic prop/response types actually infer correctly at call sites, not just that the runtime behavior works. Source files are short and single-purpose, error paths in controls.ts guard against double-resolving an already-settled Promise, and naming is consistent (proceed/cancel/dismiss mirror Promise.resolve/reject semantics throughout). No linter or formatter config was found in the repo.

What Makes It Unique Most confirmation-dialog libraries either ship their own dialog UI or bind a specific state-management pattern to the caller. react-confirm instead treats “turn a component into an awaitable function” as the entire product: it imposes no markup, no CSS, and no required state container, and the same primitive scales from a plain boolean window.confirm() replacement up to a fully typed multi-field response object via TypeScript generics threading through ConfirmDialogProps<P, R>. The external controls module — letting unrelated code resolve or dismiss a dialog it doesn’t hold a direct reference to, only a Promise — is a comparatively uncommon capability among comparable libraries.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search