react-confirm-alert

API

Every export, with a live example and its options.

Press a button to open the dialog and see what it returns. Each section ends with its options.

confirm

Resolves true from the confirm button and false otherwise. tone: 'danger' makes the button red and focuses Cancel.

confirm.tsx
'use client'
import { confirm } from 'react-confirm-alert'

export const deleteFile = () =>
  confirm({
    title: 'Delete “Q3 report.pdf”?',
    message: 'It moves to the trash for 30 days.',
    tone: 'danger',
    confirmLabel: 'Delete',
  })

A button that waits

When onConfirm returns a Promise, the button shows a spinner and the dialog stays open until it settles.

publish.tsx
'use client'
import { confirm } from 'react-confirm-alert'

const save = () => new Promise<void>((r) => setTimeout(r, 1500))

export const publish = () =>
  confirm({
    title: 'Publish changes?',
    confirmLabel: 'Publish',
    onConfirm: save,
  })
OptionTypeWhat it does
confirmLabelReactNodeConfirm button text. Default 'Confirm'.
cancelLabelReactNodeCancel button text. Default 'Cancel'.
tone'default' | 'danger''danger' paints the button red and focuses Cancel.
onConfirm(ctx) => void | PromiseRuns on confirm. A Promise keeps the dialog open. ctx.signal aborts if it closes another way.

confirm('Delete?') takes a title as a string. Every call also takes the shared options.

alert

Resolves when the dialog closes, from the button, Escape or a click outside.

alert.tsx
'use client'
import { alert } from 'react-confirm-alert'

export const showSaved = () =>
  alert({ title: 'Saved', message: 'Your changes are safe.' })
OptionTypeWhat it does
okLabelReactNodeButton text. Default 'OK'.

prompt

Resolves the text, or null on Cancel, Escape and a click outside. Return a message from validate to keep the dialog open.

prompt.tsx
'use client'
import { prompt } from 'react-confirm-alert'

export const renameFile = () =>
  prompt({
    title: 'Rename file',
    defaultValue: 'Q3 report.pdf',
    validate: (name) => (name.trim() ? null : 'Give it a name'),
  })
OptionTypeWhat it does
labelReactNodeLabel above the input.
defaultValuestringText the input starts with.
validate(value) => string | nullA message keeps the dialog open and shows under the input. Can be async.
inputPropsinput attributesSuch as type, placeholder or maxLength.
submitLabelReactNodeSubmit button text. Default 'OK'.
cancelLabelReactNodeCancel button text. Default 'Cancel'.

openDialog

Renders your component in a dialog. result resolves what you pass to close(), or undefined on Escape and outside clicks.

open-dialog.tsx
'use client'
import { DialogLayout, openDialog } from 'react-confirm-alert'

const plans = ['Free', 'Pro', 'Team']

export const pickPlan = () =>
  openDialog<string>({
    render: ({ close }) => (
      <DialogLayout
        title="Pick a plan"
        message="You can change it at any time."
        actions={plans.map((plan) => ({
          label: plan,
          onClick: () => close(plan),
        }))}
      />
    ),
  }).result
OptionTypeWhat it does
render(props) => ReactNodeYour content. props.close(value) resolves it, props.dismiss() resolves undefined.
buttonsDialogButton[]Passed to render, for a layout of your own.

openDialog() returns a handle:

FieldTypeWhat it does
resultPromise<R | undefined>Resolves when the dialog closes.
close(value: R) => voidCloses with a value.
dismiss() => voidCloses with undefined.
update(patch) => voidChanges options of the open dialog.
idDialogIdFor closeDialog(id).

closeDialog and closeAll

closeAll() dismisses every dialog, queued ones too. A confirm resolves false.

close-all.tsx
'use client'
import { closeAll, confirm } from 'react-confirm-alert'

export function askThenClose() {
  setTimeout(closeAll, 2000)
  return confirm('This closes in 2 seconds')
}
FunctionWhat it does
closeAll()Dismisses every open and queued dialog.
closeDialog(id)Dismisses one dialog, by the id of its handle.

Dialog

Renders in place and opens while open is true, so its content reads your component's state. Plain HTML inside gets the default look.

dialog.tsx
'use client'
import { useState } from 'react'
import { Dialog, DialogLayout } from 'react-confirm-alert'

export function EditNote() {
  const [open, setOpen] = useState(false)
  const [note, setNote] = useState('')
  return (
    <>
      <button onClick={() => setOpen(true)}>Edit note</button>
      <output>{note}</output>
      <Dialog open={open} onOpenChange={setOpen}>
        <DialogLayout
          title="Edit note"
          message={`${note.length} characters`}
          actions={[{ label: 'Done', onClick: () => setOpen(false) }]}
        >
          <textarea
            aria-label="Note"
            value={note}
            onChange={(e) => setNote(e.target.value)}
          />
        </DialogLayout>
      </Dialog>
    </>
  )
}
PropTypeWhat it does
openbooleanShows the dialog.
onOpenChange(open) => voidCalled with false on Escape and outside clicks.
childrenReactNodeYour content. DialogLayout lays it out.
aria-labelstringNames the dialog when there is no DialogLayout title.
aria-labelledbystringThe id of your own title.

It also takes modal, closeOnEscape, closeOnClickOutside, onKeyDown, unstyled and classNames from the shared options.

ConfirmDialog

confirm, alert or prompt, rendered in place. Pick one with kind.

confirm-dialog.tsx
'use client'
import { useState } from 'react'
import { ConfirmDialog } from 'react-confirm-alert'

export function LeavePage() {
  const [open, setOpen] = useState(false)
  const [left, setLeft] = useState(false)
  return (
    <>
      <button onClick={() => setOpen(true)}>Leave page</button>
      <output>{left && 'onConfirm ran'}</output>
      <ConfirmDialog
        kind="confirm"
        open={open}
        onOpenChange={setOpen}
        title="Leave without saving?"
        confirmLabel="Leave"
        onConfirm={() => setLeft(true)}
      />
    </>
  )
}
PropTypeWhat it does
kind'confirm' | 'alert' | 'prompt'Which dialog it is.
openbooleanShows the dialog.
onOpenChange(open) => voidCalled with false when any button or key closes it.
onSubmit(value) => void | PromisePrompt only. The text, on submit.

Every option of that kind works as a prop, such as onConfirm, tone or validate.

DialogLayout

Lays out a title, a message, your content and a row of buttons. An action whose onClick returns a Promise is busy until it settles. Use it in openDialog, <Dialog> and customUI.

dialog-layout.tsx
'use client'
import { DialogLayout, openDialog } from 'react-confirm-alert'

const save = () => new Promise((r) => setTimeout(r, 1500))

export const renameWorkspace = () =>
  openDialog({
    render: ({ close, dismiss }) => (
      <DialogLayout
        title="Rename workspace"
        message="Everyone in it sees the new name."
        actions={[
          { label: 'Cancel', onClick: dismiss },
          {
            label: 'Save',
            variant: 'primary',
            onClick: () => save().then(() => close()),
          },
        ]}
      >
        <input aria-label="Name" defaultValue="Acme" />
      </DialogLayout>
    ),
  }).result
PropTypeWhat it does
titleReactNodeHeading. It names the dialog when there is no aria-label.
messageReactNodeText under the title.
actionsDialogAction[]The buttons, left to right.
childrenReactNodeYour content, between the message and the buttons.

Each action takes:

FieldTypeWhat it does
labelReactNodeButton text.
variant'primary' | 'secondary' | 'danger'Button colour. Default 'secondary'.
onClick(event) => void | PromiseA Promise makes the button busy until it settles.

Any other button attribute, such as type="submit" or disabled, goes on the button.

DialogHost and useDialog

Dialogs render where you place <DialogHost />, so they read the context above it. This site places one inside its theme provider, so the dialog below reads the theme. Switch the theme and open it again.

dialog-host.tsx
'use client'
import { useTheme } from 'next-themes'
import { alert } from 'react-confirm-alert'

export function ThemeName() {
  const theme = useTheme().resolvedTheme ?? 'light'
  return <p>This site is in {theme} mode.</p>
}

export function ShowTheme() {
  return (
    <button onClick={() => alert({ title: 'Theme', content: <ThemeName /> })}>
      Show theme
    </button>
  )
}
app/providers.tsx
<ThemeProvider>
  {children}
  <DialogHost dismissKey={usePathname()} />
</ThemeProvider>
PropTypeWhat it does
dismissKeyunknownWhen it changes, every dialog closes. Pass the pathname.

Place one host. Without one, dialogs render in a root of their own and miss your context. The Next.js recipe shows where. useDialog() returns confirm, alert, prompt, openDialog and closeAll, for code that prefers a hook.

configureDialogs

Sets defaults for every dialog. Call it once, where your app starts.

configure-dialogs.tsx
'use client'
import { configureDialogs, confirm } from 'react-confirm-alert'

// Call once, where your app starts.
export const setThaiLabels = () =>
  configureDialogs({ labels: { confirm: 'ลบ', cancel: 'ยกเลิก' } })

export const deleteInThai = () =>
  confirm({ title: 'ลบไฟล์นี้ไหม', tone: 'danger' })
OptionTypeWhat it does
labels{ ok, confirm, cancel, submit }Default button text.
modalbooleanNative modal <dialog>. Default true.
strategy'stack' | 'queue' | 'replace'What a new dialog does when one is open. Default 'stack'.
closeOnEscapebooleanDefault true.
closeOnClickOutsidebooleanDefault true.
lockScrollbooleanStops the page from scrolling behind a dialog. Default true.
unstyledbooleanDrops the default CSS classes.
classNamesDialogClassNamesA class per slot. See Styling.
confirmAlertobjectSeparate skin, modal, strategy, unstyled and classNames for confirmAlert.

Options every dialog takes

confirm, alert, prompt and openDialog take these.

OptionTypeWhat it does
titleReactNodeHeading.
messageReactNodeText under the title. A string keeps its line breaks.
contentReactNodeYour JSX between the message and the buttons.
closeOnEscapebooleanDefault true.
closeOnClickOutsidebooleanDefault true.
strategy'stack' | 'queue' | 'replace'stack opens on top, the default. queue waits its turn. replace closes the open one.
modalbooleanfalse renders a plain overlay instead of a top-layer <dialog>.
signalAbortSignalAborting it dismisses the dialog.
onKeyDown(event, close) => voidYour own keys. close() dismisses.
afterClose() => voidRuns once the dialog has closed.
unstyledbooleanDrops the default CSS classes.
classNamesDialogClassNamesA class per slot. See Styling.

confirmAlert

The 3.0 API, with its 3.0 look and timing. It returns nothing; each button runs its own onClick.

confirm-alert.tsx
'use client'
import { confirmAlert } from 'react-confirm-alert'

export function SubmitOrder() {
  return (
    <button
      onClick={() =>
        confirmAlert({
          title: 'Confirm to submit',
          message: 'Are you sure to do this?',
          buttons: [{ label: 'Yes' }, { label: 'No' }],
        })
      }
    >
      Submit
    </button>
  )
}

customUI

customUI replaces the whole dialog with your content. skin: true puts it in the new dialog body, where plain HTML gets the default look. Custom UI has more.

custom-ui.tsx
'use client'
import { confirmAlert } from 'react-confirm-alert'

export function ShowTerms() {
  return (
    <button
      onClick={() =>
        confirmAlert({
          skin: true,
          customUI: ({ onClose }) => (
            <>
              <h1>Terms updated</h1>
              <p>Read what changed before you go on.</p>
              <button data-variant="primary" onClick={onClose}>
                Got it
              </button>
            </>
          ),
        })
      }
    >
      Show terms
    </button>
  )
}
OptionTypeWhat it does
titlestringHeading.
messagestringText under the title.
buttonsobject[]Each has label, onClick and className. Every button closes the dialog. Default Cancel and Confirm.
customUI(props) => ReactNodeReplaces the dialog content. props.onClose() closes it.
skinbooleanThe new look, with customUI too. Default false.
childrenElement() => ReactNodeRenders under the message.
closeOnEscapebooleanDefault true.
closeOnClickOutsidebooleanDefault true.
onClickOutside() => voidRuns on a click outside.
onKeypressEscape(event) => voidRuns on Escape.
onkeyPress(event, close) => voidRuns on any key.
willUnmount() => voidRuns before the dialog unmounts.
afterClose() => voidRuns after it closes.
overlayClassNamestringA class on the overlay.
targetIdstringRenders into the element with this id.
modalbooleanNative modal <dialog>. Default false.
strategy'replace' | 'stack' | 'queue'Default 'replace': a new dialog closes the open one.
unstyledbooleanDrops the 3.0 classes.
classNamesDialogClassNamesA class per slot.

On this page