Dialog & DialogProvider
A promise-based imperative dialog system for confirmations, alerts, and critical user interactions. Rather than cluttering your component trees with repetitive useState boilerplate, DialogProvider lets you invoke asynchronous modal dialogs imperatively with await nui.confirm() and await nui.alert().
import { DialogProvider, nui } from '@nofinite/nui';Interactive Preview
Architecture Overview
The NUI Dialog architecture decouples the dialog triggering logic from the React rendering tree:
┌───────────────────────────────┐
│ Event Handler / Server Action │
│ await nui.confirm(...) │
└───────────────┬───────────────┘
│ Dispatches via external store
▼
┌───────────────────────────────┐
│ <DialogProvider /> (Root) │
│ Mounts Modal & Traps Focus │
└───────────────┬───────────────┘
│ Resolves Promise on User Action
▼
┌───────────────────────────────┐
│ isConfirmed === true / false │
└───────────────────────────────┘- Mount
<DialogProvider />Once: Place at your application root (e.g.layout.tsx). - Call Anywhere: Trigger
nui.confirm(...)ornui.alert(...)anywhere in client handlers, async utilities, or data-fetching interceptors. - Promise-Driven Flow: Await the user's decision without managing local open/close state.
Root Setup
Mount <DialogProvider /> once in your root layout:
// app/layout.tsx (Next.js App Router)
import { DialogProvider } from '@nofinite/nui';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
{children}
<DialogProvider />
</body>
</html>
);
}Dialog Types & Usage
Destructive Confirm Dialog
Use nui.confirm() to ask users for explicit confirmation before carrying out irreversible actions:
'use client';
import { nui, Button } from '@nofinite/nui';
export function DeleteAccountButton() {
const handleDelete = async () => {
const isConfirmed = await nui.confirm(
'Are you absolutely sure? All data associated with this account will be permanently erased.',
{
title: 'Delete Account',
confirmText: 'Yes, Delete',
cancelText: 'Cancel',
isDanger: true,
}
);
if (isConfirmed) {
// Proceed with deletion API call
nui.success('Account deleted successfully.');
} else {
nui.toast('Deletion cancelled.');
}
};
return (
<Button variant="danger" onClick={handleDelete}>
Delete Account
</Button>
);
}Informational Alert Dialog
Use nui.alert() when the user must acknowledge important information or terms before proceeding:
'use client';
import { nui, Button } from '@nofinite/nui';
export function TermsDialogButton() {
const handleShowTerms = async () => {
await nui.alert(
'By clicking continue, you agree to our updated Terms of Service and Privacy Policy.',
{
title: 'Terms of Service Update',
confirmText: 'I Understand',
}
);
console.log('Terms acknowledged');
};
return (
<Button variant="outline" onClick={handleShowTerms}>
Review Policy Update
</Button>
);
}Dialog Options Reference
nui.confirm(message, options) and nui.alert(message, options) accept an optional configuration object:
| Option | Type | Default | Description |
|---|---|---|---|
title | string | 'Confirm' / 'Alert' | The heading displayed at the top of the dialog |
confirmText | string | 'Confirm' / 'OK' | Label for the primary action button |
cancelText | string | 'Cancel' | Label for the cancel button (confirm dialogs only) |
isDanger | boolean | false | When true, renders the primary button with variant="danger" |
Keyboard Interaction
| Key | Behavior |
|---|---|
| Tab | Cycles focus between active dialog buttons |
| Shift + Tab | Reverse cycles focus |
| Enter | Activates the currently focused button |
| Escape | Dismisses alert dialogs (confirm dialogs disable outside dismissal to prevent accidents) |
Accessibility
- Automatically traps keyboard focus within the dialog container while active.
- Employs semantic dialog roles (
role="alertdialog"for destructive confirms). - Disables background scrolling and backdrop interaction while open.
- Restores focus to the triggering element upon dialog dismissal.
Best Practices
Do
- Mount
<DialogProvider />once at the application root. - Use
isDanger: truefor permanent or destructive flows (deleting databases, removing team members). - Pair
nui.confirm()withnui.toast()ornui.success()to deliver instant feedback upon resolution. - Keep dialog messages clear, unambiguous, and concise.
Don't
- Do not mount multiple
<DialogProvider />instances across nested routes. - Do not trigger dialogs synchronously during component rendering; always invoke within event handlers or effects.
- Avoid using confirm dialogs for minor or easily undoable operations.
API Reference
Inherits all standard attributes and event handlers from { children?: React.ReactNode } — Mount once at app root to enable imperative dialogs (nui.alert, nui.confirm). Supports className for semantic NUICSS superclasses and ref forwarding.