npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nuxt-confirm-dialog

v1.1.0

Published

A beautiful, framework-agnostic confirm dialog module for Nuxt 3 and Nuxt 4 — no Vuetify required.

Readme

nuxt-confirm-dialog

CI License: MIT

A beautiful, zero-dependency confirm dialog module for Nuxt 3 and Nuxt 4 — no Vuetify or icon-font required. Drop it in, call useConfirmDialog().confirmDelete(...), await the result.

Confirm Deletion dialog: red border, trash icon in a half-arc circle, "This action cannot be undone" warning, Cancel + Delete buttons

  • 🎨 Polished look — dark radial gradient, colored borders per type, decorative top icon, blurred backdrop
  • 🧩 Standalone — no Vuetify, no MDI, no extra CSS framework
  • ⚡️ Auto-mounted — no boilerplate, just call useConfirmDialog().confirmDelete('item')
  • 🎯 Promise-based APIawait dialog.show({...}) returns the action; convenience methods return boolean
  • 🧠 Fully typed — written in TypeScript with full IntelliSense
  • 🔘 1 / 2 / 3 button layouts — default Cancel/Confirm or custom buttons with named actions
  • ⌨️ Keyboard friendlyEsc cancels, focus is trapped while open and restored on close
  • 🔤 Modern typography — bundled Shabnam for Persian/Arabic + Inter for Latin (both opt-out)
  • 🌐 Auto RTL — dialogs containing Arabic/Persian script switch to dir="rtl" automatically
  • Accessiblerole="alertdialog", aria-modal, aria-labelledby, aria-describedby

Table of contents

For deeper technical reference (architecture, design rationale, contributing), see docs/.


Installation

npm install nuxt-confirm-dialog
# or
pnpm add nuxt-confirm-dialog
# or
yarn add nuxt-confirm-dialog
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['nuxt-confirm-dialog'],
})

That's it — useConfirmDialog() is auto-imported and a <ConfirmDialogContainer> is mounted automatically on the client.


Quick start

<script setup lang="ts">
const dialog = useConfirmDialog()

const onDelete = async () => {
  if (await dialog.confirmDelete('user "alice"')) {
    await api.deleteUser('alice')
  }
}

const onSave = async () => {
  const action = await dialog.show({
    type: 'info',
    title: 'Save changes?',
    message: 'You have unsaved edits.',
    buttons: [
      { text: 'Cancel',     action: 'cancel',  variant: 'outlined', color: 'default' },
      { text: "Don't save", action: 'discard', variant: 'flat',     color: 'default' },
      { text: 'Save',       action: 'save',    variant: 'flat',     color: 'info' },
    ],
  })
  // action: 'cancel' | 'discard' | 'save'
}
</script>

<template>
  <button @click="onDelete">Delete</button>
  <button @click="onSave">Save</button>
</template>

The bundled playground exercises every feature — convenience methods, custom show(), custom buttons, and Persian RTL:

Quick demo page with the four convenience-method buttons and the custom show() controls


Module options

Configure under the confirmDialog key in nuxt.config.ts:

export default defineNuxtConfig({
  modules: ['nuxt-confirm-dialog'],
  confirmDialog: {
    autoMount: true,
    closeOnBackdropClick: false,
    escapeToCancel: true,
    prefix: 'Confirm',
    loadShabnamFont: true,
    loadInterFont: true,
  },
})

| Option | Type | Default | Description | | ---------------------- | --------- | ----------- | ----------- | | autoMount | boolean | true | When true, mounts a <ConfirmDialogContainer> automatically on the client. Set false to mount it yourself. | | closeOnBackdropClick | boolean | false | If true, clicking the dim backdrop cancels the dialog. Default is persistent (clicks on the backdrop are ignored). | | escapeToCancel | boolean | true | If true, pressing the Escape key cancels the dialog. | | prefix | string | 'Confirm' | Component name prefix. Default makes components <ConfirmDialog> and <ConfirmDialogContainer>. | | theme | 'dark' \| 'light' | 'dark' | Initial visual theme. Switch at runtime with useConfirmDialog().setTheme(...) or override per-container with the theme prop. | | loadShabnamFont | boolean | true | Inject the bundled Persian "Shabnam" font (5 weights, woff2). unicode-range ensures the file is only downloaded when Arabic/Persian script appears. | | loadInterFont | boolean | true | Add Inter (Google Fonts) as the modern English UI typeface via a <link> in the head. |


Composable API — useConfirmDialog()

const dialog = useConfirmDialog()

show(options)

Display a dialog. Returns Promise<string> resolving with the action name — 'confirm', 'cancel', or any custom action you defined in the buttons array. The promise always resolves — it never rejects.

const action = await dialog.show({
  type: 'warning',
  title: 'Heads up',
  message: 'Continue?',
  warningText: 'This will replace existing data.',
})
if (action === 'confirm') { /* user confirmed */ }

| Option | Type | Required | Default | | ------------- | ----------------------------------------------- | -------- | ------------- | | type | 'success' \| 'warning' \| 'error' \| 'info' | no | 'warning' | | title | string | yes | — | | message | string | yes | — | | warningText | string \| null | no | null | | confirmText | string | no | 'Confirm' | | cancelText | string | no | 'Cancel' | | buttons | ConfirmDialogButton[] \| null | no | null |

Convenience methods

All return Promise<boolean>true if the user confirms, false otherwise.

await dialog.confirmDelete(itemName?, customMessage?, customWarning?)  // red theme
await dialog.confirmAction(title, message, confirmText?, cancelText?)  // yellow theme
await dialog.confirmInfo(title, message, confirmText?, cancelText?)    // cyan theme
await dialog.confirmSuccess(title, message, confirmText?, cancelText?) // green theme

currentDialog

Reactive Ref<ConfirmDialogInstance | null> holding the active dialog. Useful for custom containers or status indicators.

<span v-if="dialog.currentDialog.value">Dialog is open</span>

Internal action methods

confirm(), cancel(), action(name) — these are called by the container to settle the active promise. You rarely need them directly unless building a custom container.


Custom buttons

Pass a buttons array to override the default Cancel/Confirm pair. Supports 1, 2, or 3 buttons. Each button is { text, action?, variant?, color? }:

await dialog.show({
  type: 'info',
  title: 'Save changes?',
  message: 'You have unsaved edits.',
  buttons: [
    { text: 'Cancel',     action: 'cancel',  variant: 'outlined', color: 'default' },
    { text: "Don't save", action: 'discard', variant: 'flat',     color: 'default' },
    { text: 'Save',       action: 'save',    variant: 'flat',     color: 'info' },
  ],
})
// resolves with 'cancel' | 'discard' | 'save'

Three-button dialog showing Cancel, Don't save, and Save laid out in a CSS grid

| Field | Type | Default | | --------- | ------------------------------------------------------------- | -------------------------------------- | | text | string | required | | action | string | 'confirm' | | variant | 'flat' \| 'outlined' | 'outlined' for cancel, else 'flat' | | color | 'success' \| 'warning' \| 'error' \| 'info' \| 'default' | dialog type for confirm buttons |


Component API

<ConfirmDialogContainer>

The container that renders the active dialog. Auto-mounted by default — only use this directly if autoMount: false.

| Prop | Type | Default | Description | | ---------------------- | --------- | ------- | ----------- | | teleport | boolean | true | Render into document.body via <Teleport> so the overlay always covers the viewport. Disable only for special cases. | | closeOnBackdropClick | boolean | false | Backdrop click cancels the dialog. | | escapeToCancel | boolean | true | Escape key cancels the dialog. |

<ConfirmDialog>

The single-dialog component. You normally don't render this directly — useConfirmDialog() and <ConfirmDialogContainer> handle it. Exposed for static / non-composable usage.

Props mirror show(options) plus modelValue (boolean) for v-model. Emits: update:modelValue, confirm, cancel, action.

<ConfirmDialog
  v-model="open"
  type="error"
  title="Delete file?"
  message="This is permanent."
  @confirm="handleConfirm"
  @cancel="handleCancel"
/>

Types

| Type | Color (border + icon) | Recommended use | | ----------- | --------------------- | ---------------------------------------------- | | success | #30e0a1 (green) | Positive confirmation (publish, complete) | | warning | #FFD700 (yellow) | Default — caution required | | error | #DC143C (red) | Destructive actions (delete, reset) | | info | #00FFFF (cyan) | Informational confirmations |

Each type has a matching inline SVG icon (no icon-font required).


Theme

Ships with a dark theme (default) and a light theme. Switch globally at runtime, or override per-container.

// nuxt.config.ts — initial theme
confirmDialog: { theme: 'light' }
<script setup lang="ts">
const dialog = useConfirmDialog()

console.log(dialog.theme.value) // 'dark' or 'light'

dialog.setTheme('light')

// Optional: follow the user's system preference
const sync = () => dialog.setTheme(
  window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light',
)
sync()
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', sync)
</script>

Per-container override (useful for an always-light dialog inside a dark dashboard):

<ConfirmDialogContainer theme="light" />

The theme prop, when set, takes precedence over useConfirmDialog().theme. The four type-color borders (#30e0a1 / #FFD700 / #DC143C / #00FFFF) stay constant in both themes — only the card background, overlay backdrop, message text, and outlined button neutrals swap.


Customization

The auto-mounted container lives at #nuxt-confirm-dialog-root. Override styles globally by targeting that root:

/* assets/css/main.css */
#nuxt-confirm-dialog-root .dialog-card {
  max-width: 560px;
  border-radius: 16px;
}

#nuxt-confirm-dialog-root .dialog-error {
  border-color: #ef4444;
}

Fonts

Two fonts are loaded by default:

  • Inter (English / Latin) — Google Fonts via <link>. Disable with loadInterFont: false.
  • Shabnam (Persian / Arabic) — bundled woff2 (5 weights), gated by unicode-range. Disable with loadShabnamFont: false.

The dialog uses the same stack as the nuxt-toast-notification library:

font-family:
  'Inter',
  'Shabnam',
  system-ui,
  -apple-system,
  BlinkMacSystemFont,
  'Segoe UI Variable Text',
  'Segoe UI',
  Roboto,
  'Helvetica Neue',
  Arial,
  sans-serif;

Right-to-left support

When the title, message, or warning text contains Arabic / Persian script, the dialog auto-switches to dir="rtl". The detection is per-instance — you can mix LTR and RTL dialogs in the same app without configuration.

Persian delete confirmation: red border, trash icon, "حذف فایل" title, RTL button order with حذف on the left and انصراف on the right, rendered with the bundled Shabnam font

Manual mounting

// nuxt.config.ts
confirmDialog: { autoMount: false }
<!-- app.vue -->
<template>
  <NuxtLayout><NuxtPage /></NuxtLayout>
  <ConfirmDialogContainer />
</template>

The state is global — multiple containers all subscribe to the same active dialog (only one dialog can be active at a time, by design).


TypeScript

The module ships full type definitions:

import type {
  ConfirmDialogType,         // 'success' | 'warning' | 'error' | 'info'
  ConfirmDialogOptions,      // arg shape for show()
  ConfirmDialogButton,       // { text, action?, variant?, color? }
  ConfirmDialogInstance,     // shape of currentDialog.value
} from 'nuxt-confirm-dialog'

ModuleOptions is also exported.


Development

npm install
npm run dev:prepare
npm run dev            # playground at http://localhost:3000

npm run lint
npm run test
npm run prepack        # build dist/

The playground at playground/ exercises every feature — types, button configurations, real-world examples, and Persian / RTL.

CI

GitHub Actions runs lint (Node 22) and tests + build (Node 20 and 22) on every push and PR against main.


License

MIT