Skip to content

A lightweight, promise-based confirm dialog for React with built-in Tailwind CSS support. Designed to be as easy to use as `react-toastify`, while remaining fully customizable.

License

Notifications You must be signed in to change notification settings

SaadNasir-git/react-confirm-lite

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

3 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

React Confirm Lite ✨

A lightweight, promise-based confirm dialog for React, designed to be as easy to use as react-toastify, while remaining fully customizable.

npm version bundle size npm downloads license typescript react

Sample Image

Note:

  • Try not to use versions 1.4.0 , 1.4.1 and 1.4.2 .

πŸ”— Live Demo

Open in StackBlitz

πŸ“¦ Installation

npm install react-confirm-lite
# or
yarn add react-confirm-lite
# or
pnpm add react-confirm-lite

πŸš€ Quick Start

Complete Example

Place <ConfirmContainer /> in your app (usually in root layout) and use it with confirm

import { ConfirmContainer, confirm } from 'react-confirm-lite';

function App() {
  async function handleAction() {
    const result = await confirm('Are you sure?');
    
    if (result) {
      console.log('User confirmed!');
    } else {
      console.log('User cancelled!');
    }
  }
  return (
    <div>
      {/* Your app content */}
      <ConfirmContainer />
    </div>
  );
}

Important

By default it shows the closest container to button to which you clicked to show the confirmation dialog but you are a programmer and you will try thing and sometimes you may use it in useEffect hook then in this case it will show the first rendered confirm container.

If you want to show a specific container by confirm api no matters where it is then you can pass the id like this

// In confirm Api
confirm({id:'1' , message:'Are you sure?'})
// And in confirm Container
<ConfirmContainer id='1'/>

And make sure that not to pass same id to different <ConfirmContainer /> In this way It will show both of these containers

🎯 Features

βœ… Simple Promise-based API

const result = await confirm('Message here');
// Returns true for OK, false for Cancel, null for ESC/outside click

βœ… 18 Built-in Animations

Choose from various animations:

  • slide (default) - Smooth slide up/down
  • fadeScale - Fade with scale effect
  • bounce - Playful bounce animation
  • flip - 3D flip effect
  • zoom - Zoom in/out
  • rotate - Rotate animation
  • fadeUp / fadeDown - Directional fade
  • drop - 3D drop effect
  • slideRight / slideLeft - Horizontal slides
  • slideVertical - Vertical slide
  • slideDown - Slide down
  • rotateRight - Rotate from right
  • zoomSmall / bounceSmall - Subtle animations
  • fadeBlur / fadeShrink - Creative effects

βœ… 6 Color Schemes

Pre-built color themes:

  • dark (default) - Dark theme
  • light - Light theme
  • blue - Blue theme
  • red - Perfect for destructive actions
  • green - Success actions
  • purple - Premium/feature actions

βœ… Interactive Controls

  • closeOnEscape (default: true) - Press ESC to close
  • closeOnClickOutside (default: true) - Click backdrop to close
  • Returns null when closed via ESC or backdrop click

βœ… Customizable Options

Control every aspect:

  • Custom OK/Cancel button text
  • Separate animation durations for enter/exit
  • Override colors per dialog
  • Custom CSS classes for all elements

βœ… Queue System

Multiple confirm requests automatically queue and show one at a time:

// These will show sequentially
await confirm('First?');
await confirm('Second?');
await confirm('Third?');

βœ… Zero Configuration

No CSS imports needed. Styles are automatically injected.

🎨 Usage Examples

Basic Usage

const result = await confirm('Delete this item?');
if (result) {
  // User clicked OK
  deleteItem();
} else if (result === false) {
  // User clicked Cancel
  console.log('Cancelled');
} else if (result === null) {
  // User pressed ESC or clicked outside
  console.log('Closed via ESC/backdrop');
}

Custom Dialog Options

const result = await confirm({
  title: 'Delete Account',
  message: 'This will permanently delete your account and all data.',
  okText: 'Delete Forever',
  cancelText: 'Cancel',
  colorSchema: 'red'
});

Disable ESC and Backdrop Closing

<ConfirmContainer 
  closeOnEscape={false}
  closeOnClickOutside={false}
/>
// Now dialog can only be closed with Cancel/OK buttons

πŸ”§ API Reference

Confirm Container Props

Prop Type Default Description
id string random To show a specific container with a specific confirm() app
animation AnimationType 'slide' Animation type (18 options)
animationDuration number 300 Base animation duration (ms)
animationDurationIn number - Enter animation duration
animationDurationOut number - Exit animation duration
defaultColorSchema ColorSchema 'dark' Default color scheme
closeOnEscape boolean true Close with ESC key
closeOnClickOutside boolean true Close on backdrop click
classes ConfirmClasses {} Custom CSS classes

Confirm Function

// String input (simple)
await confirm('Simple message');

// Object input (full options)
await confirm({
  title: 'Custom Title',           // Optional
  message: 'Required message',     // Required
  okText: 'Proceed',               // Optional
  cancelText: 'Go Back',           // Optional
  colorSchema: 'blue',             // Optional
});

Return values:

  • true - User clicked OK
  • false - User clicked Cancel
  • null - User pressed ESC or clicked outside (if enabled)

Custom Styling with CSS Classes

<ConfirmContainer 
  classes={{
    overlay: "my-overlay-class",    // Background overlay
    wrapper: "my-modal-class",      // Modal container
    title: "my-title-class",        // Title text
    message: "my-message-class",    // Message text
    button: "my-button-class",      // Both buttons
    cancel: "my-cancel-class",      // Cancel button only
    ok: "my-ok-class",              // OK button only
  }}
/>

🎭 Custom UI with Render Prop

Want complete control over the UI? Use the render prop:

<ConfirmContainer animationDuration={500}>
  {({ 
    isVisible, 
    confirm, 
    handleCancel, 
    handleOk, 
    containerRef, 
    animationClass, 
    animationStyle 
  }) => (
    <div className={`modal-overlay ${isVisible ? 'show' : 'hide'}`}>
      {/* Your custom backdrop */}
      <div className="backdrop" onClick={handleCancel} />
      
      {/* Your custom modal */}
      <div 
        ref={containerRef}
        className={`custom-modal ${animationClass}`}
        style={animationStyle}
      >
        <h2>{confirm.title}</h2>
        <p>{confirm.message}</p>
        
        <div className="buttons">
          <button onClick={handleCancel}>
            {confirm.cancelText || 'Cancel'}
          </button>
          <button onClick={handleOk}>
            {confirm.okText || 'OK'}
          </button>
        </div>
      </div>
    </div>
  )}
</ConfirmContainer>

Available render props:

  • isVisible: Boolean indicating if dialog should be visible
  • confirm: The current confirm options object
  • handleCancel: Function to cancel the dialog (returns false)
  • handleOk: Function to confirm the dialog (returns true)
  • containerRef: React ref for the modal container
  • colorSchema: Current color scheme
  • animationClass: CSS class for current animation
  • animationStyle: Style object with animation duration
  • lockScroll: Boolean, If will be true then scroll will be locked when dialog will show.

πŸ“± Real-World Examples

Delete Confirmation with ESC Disabled

const handleDelete = async () => {
  // Force user to make explicit choice
  const result = await confirm({
    title: 'Delete Item',
    message: 'This action cannot be undone. Are you sure?',
    okText: 'Delete',
    cancelText: 'Keep',
    colorSchema: 'red'
  });

  // Result can only be true or false (no null since ESC/backdrop disabled)
  if (result) {
    await deleteItem();
  }
};

// In your component
<ConfirmContainer closeOnEscape={false} closeOnClickOutside={false} />

Form Submission with Backdrop Only

// Allow closing by clicking backdrop but not ESC
<ConfirmContainer closeOnEscape={false} closeOnClickOutside={true} />

const handleSubmit = async () => {
  const result = await confirm({
    title: 'Submit Form',
    message: 'Ready to submit this form?',
    okText: 'Submit',
    cancelText: 'Review',
    colorSchema: 'green'
  });

  if (result) {
    await submitForm();
  } else if (result === null) {
    // User clicked backdrop
    console.log('Closed by clicking outside');
  }
};

Different Behaviors for Different Dialogs

// Global: ESC and backdrop disabled
<ConfirmContainer 
  closeOnEscape={false} 
  closeOnClickOutside={false} 
/>

// Some dialogs can override via custom UI
const handleFlexibleDialog = async () => {
  // Create custom UI that allows ESC/backdrop
  const result = await confirm('Flexible dialog?');
  // result can be true, false, or null
};

πŸ—οΈ Container Configuration

Global Settings

<ConfirmContainer
  defaultColorSchema="light"        // Light theme by default
  animation="zoom"                  // Zoom animation for all dialogs
  animationDuration={400}           // 400ms animations
  closeOnEscape={true}              // Allow ESC to close
  closeOnClickOutside={true}        // Allow backdrop click to close
  animationDurationIn={350}         // Enter: 350ms
  animationDurationOut={250}        // Exit: 250ms
  lockScroll={false}                // true by default
/>

Different Close Behaviors

// Option 1: Fully closable (default)
<ConfirmContainer closeOnEscape={true} closeOnClickOutside={true} />
// Users can close via: OK, Cancel, ESC, or backdrop click

// Option 2: Force explicit choice
<ConfirmContainer closeOnEscape={false} closeOnClickOutside={false} />
// Users can only close via: OK or Cancel buttons

// Option 3: Backdrop only
<ConfirmContainer closeOnEscape={false} closeOnClickOutside={true} />
// Users can close via: OK, Cancel, or backdrop click

// Option 4: ESC only
<ConfirmContainer closeOnEscape={true} closeOnClickOutside={false} />
// Users can close via: OK, Cancel, or ESC key

If user will close dialog box by clicking outside or by pressing escape then it will return null

🎨 Animation Gallery

Slide Animations

  • slide - Smooth vertical slide (default)
  • slideRight / slideLeft - Horizontal slides
  • slideVertical - Vertical slide
  • slideDown - Slide down

Fade Animations

  • fadeScale - Fade with scaling
  • fadeUp / fadeDown - Directional fades
  • fadeBlur - Fade with blur effect
  • fadeShrink - Fade with shrink effect

3D Animations

  • flip - Card flip effect
  • drop - 3D drop animation
  • rotate / rotateRight - Rotation effects

Playful Animations

  • bounce / bounceSmall - Bounce effects
  • zoom / zoomSmall - Zoom in/out

🚨 Troubleshooting

Multiple dialogs are showing?

  • Make sure you are on version >=1.4
  • Make sure you didn't pass same id to different <ConfirmContainer />

Dialog not showing?

  • Make sure <ConfirmContainer /> is mounted
  • Check it's not conditionally rendered

ESC key not working?

  • Check if closeOnEscape={true} (default)
  • Ensure no other event is preventing ESC
  • Try different browsers

Backdrop click not working?

  • Verify closeOnClickOutside={true} (default)
  • Check if any parent element is preventing clicks

Animation not working?

  • Verify animation name is correct
  • Check browser console for errors

TypeScript errors?

  • Ensure you have @types/react installed
  • Update to latest TypeScript version

Styling issues?

  • Use classes prop to override styles
  • Check CSS specificity

You can also use it in TanStack with react easily

πŸ“± Next.js Support

App Router (Next.js 15+)

// app/layout.tsx
import { ConfirmContainer } from 'react-confirm-lite';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        {children}
        <ConfirmContainer />
      </body>
    </html>
  );
}

Server Components

// Server actions
'use server';
import { confirm } from 'react-confirm-lite';

export async function serverAction() {
  const result = await confirm('Confirm from server?');
  if (result) {
    // Perform action
  } else if (result === null) {
    // User pressed ESC or clicked outside
    console.log('Action cancelled');
  }
}

πŸ”„ Migration from Other Libraries

From window.confirm()

// Old way (always returns true/false)
if (window.confirm('Delete?')) {
  deleteItem();
}

// New way (returns true/false/null)
const result = await confirm('Delete?');
if (result === true) {
  await deleteItem();
} else if (result === false) {
  console.log('User clicked Cancel');
} else if (result === null) {
  console.log('User pressed ESC');
}

From Other Confirm Libraries

  • No CSS imports needed
  • Automatic queue system
  • Built-in animations
  • Zero configuration
  • Three return states (true/false/null)

Contributing to react-confirm-lite

Thanks for your interest in contributing. This project is intentionally lightweight, so the contribution workflow is kept simple and explicit. Please read this fully before starting.


πŸ“¦ Project Structure

react-confirm-lite/
β”œβ”€ src/               # Library source code
β”œβ”€ dist/              # Built output (generated)
β”œβ”€ example/           # Local playground app (Vite + React)
β”œβ”€ CONTRIBUTING.md
β”œβ”€ README.md
β”œβ”€ package.json
β”œβ”€ tsup.config.ts
  • src/ β†’ where you make changes
  • dist/ β†’ auto-generated by tsup (do not edit manually)
  • example/ β†’ used to test changes locally

🧰 Prerequisites

  • Node.js >= 18
  • npm >= 9
  • Basic familiarity with React + TypeScript

πŸš€ Local Development Setup

1. Clone the repository

git clone https://github.com/SaadNasir-git/react-confirm-lite.git
cd react-confirm-lite

2. Install dependencies (root)

npm install

πŸ” Development Workflow (IMPORTANT)

This project uses tsup watch mode for live rebuilding.

Terminal 1 β€” Run library in watch mode

From the project root:

npm run build:watch

This will:

  • Watch src/ for changes
  • Automatically rebuild dist/
  • Re-run post-build steps when files change

⚠️ Leave this terminal running.


Terminal 2 β€” Run example app

cd example
npm install
npm run dev

Open the provided local URL in your browser.


πŸ§ͺ How to Test Your Changes

  1. Modify files inside src/
  2. tsup automatically rebuilds the library
  3. Refresh the browser running the example app
  4. Verify behavior visually and via console logs

You do not need to:

  • run npm pack
  • reinstall the package
  • publish to npm

This setup mirrors real-world library development.


🧠 What to Change (and What Not to)

βœ… You can change

  • Logic in src/
  • Types in types.ts
  • Styles / animations
  • README documentation

❌ Do not change

  • dist/ files manually
  • Version number (maintainer handles releases)
  • Build configuration unless discussed

🧹 Code Style

  • Use TypeScript types explicitly
  • Avoid unnecessary abstractions
  • Prefer clarity over cleverness
  • Keep bundle size in mind

🐞 Reporting Bugs

When opening an issue, include:

  • What you expected
  • What actually happened
  • Steps to reproduce
  • Browser and React version

πŸ’‘ Feature Requests

Feature requests are welcome, but keep in mind:

  • This library aims to stay minimal
  • Features should not add heavy dependencies
  • API simplicity is a priority

πŸ›  Development & Contributing

If you want to contribute or modify the library locally, use the built-in example app and watch mode.

Local Development Setup

git clone https://github.com/SaadNasir-git/react-confirm-lite.git
cd react-confirm-lite
npm install

Run Library in Watch Mode

In the project root:

npm run build:watch

This watches the src/ directory and automatically rebuilds dist/ on every change.

Run Example App

In a second terminal:

cd example
npm install
npm run dev

Open the local URL shown by Vite. Any change you make in src/ will be reflected after a browser refresh.

Notes

  • Do not edit files inside dist/ manually
  • You do not need to run npm pack or reinstall the package
  • Versioning and releases are handled by the maintainer

For more details, see CONTRIBUTING.md.


πŸ“„ License

By contributing, you agree that your contributions will be licensed under the MIT License.


Thanks for contributing to react-confirm-lite πŸ™Œ

πŸ“„ License

MIT License - free for personal and commercial use.

πŸ‘¨β€πŸ’» Author

Saad Nasir - Creator of react-confirm-lite


⭐ Found this useful? Give it a star on GitHub! ⭐

About

A lightweight, promise-based confirm dialog for React with built-in Tailwind CSS support. Designed to be as easy to use as `react-toastify`, while remaining fully customizable.

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •