Getting Started
Blocks
About
The Dialog Manager is a comprehensive dialog management system that provides a simple API for creating confirm dialogs, input dialogs, and custom dialogs with global state management using Zustand.
Features
- ✅ Simple API: Easy-to-use functions for common dialog patterns
- ✅ Global State: Dialogs managed with Zustand for consistent state
- ✅ Async Support: Built-in loading states for async actions
- ✅ Queue Support: Multiple dialogs handled automatically
- ✅ Customizable: Full control over styling and behavior
- ✅ TypeScript: Fully typed for better developer experience
Preview
Dialog Manager
Programmatic dialogs with confirm, input, and custom variants
"use client"
import { Trash2 } from "lucide-react"
import { toast } from "sonner"
import { Button } from "@/components/ui/button"
import { Card } from "@/components/ui/card"
import { dialogManager } from "@/registry/nowts/blocks/dialog-manager/dialog-manager"
export function DialogManagerDemo() {
const handleConfirmDialog = () => {
dialogManager.confirm({
title: "Delete Account",
description:
"Are you sure you want to delete your account? This action cannot be undone.",
action: {
label: "Delete",
variant: "destructive",
onClick: async () => {
await new Promise((resolve) => setTimeout(resolve, 1000))
toast.success("Account deleted")
},
},
icon: Trash2,
style: "centered",
})
}
const handleInputDialog = () => {
dialogManager.input({
title: "Create Project",
description: "Enter a name for your new project",
input: {
label: "Project Name",
placeholder: "my-awesome-project",
defaultValue: "",
},
action: {
label: "Create",
onClick: async (value) => {
await new Promise((resolve) => setTimeout(resolve, 1000))
toast.success(`Project "${value}" created`)
},
},
})
}
const handleConfirmTextDialog = () => {
dialogManager.confirm({
title: "Delete Everything",
description: "This will permanently delete all your data.",
confirmText: "DELETE",
action: {
label: "Delete",
variant: "destructive",
onClick: async () => {
await new Promise((resolve) => setTimeout(resolve, 1000))
toast.success("All data deleted")
},
},
})
}
return (
<Card className="p-6">
<div className="mb-6">
<h3 className="text-lg font-semibold">Dialog Manager</h3>
<p className="text-muted-foreground text-sm">
Programmatic dialogs with confirm, input, and custom variants
</p>
</div>
<div className="grid gap-2">
<Button
onClick={handleConfirmDialog}
variant="default"
className="w-full"
>
Confirm Dialog
</Button>
<Button
onClick={handleInputDialog}
variant="secondary"
className="w-full"
>
Input Dialog
</Button>
<Button
onClick={handleConfirmTextDialog}
variant="outline"
className="w-full"
>
Confirm with Text
</Button>
</div>
</Card>
)
}
Installation
1. Install the component
pnpm dlx shadcn@latest add https://ui.nowts.app/r/dialog-manager.json
2. Add to your layout
Add the DialogManagerRenderer
to your root layout:
import { DialogManagerRenderer } from "@/lib/dialog-manager/dialog-manager-renderer"
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
{children}
<DialogManagerRenderer />
</body>
</html>
)
}
Usage
Basic confirm dialog
import { dialogManager } from "@/lib/dialog-manager/dialog-manager"
export function DeleteButton() {
const handleDelete = () => {
dialogManager.confirm({
title: "Delete Item",
description: "Are you sure you want to delete this item?",
action: {
label: "Delete",
variant: "destructive",
onClick: async () => {
await deleteItem()
},
},
})
}
return (
<Button onClick={handleDelete} variant="destructive">
Delete
</Button>
)
}
Confirm with text verification
dialogManager.confirm({
title: "Delete Account",
description:
"This action is irreversible. All your data will be permanently deleted.",
confirmText: "DELETE",
action: {
label: "Delete Account",
variant: "destructive",
onClick: async () => {
await deleteAccount()
},
},
})
Input dialog
dialogManager.input({
title: "Create Project",
description: "Enter a name for your new project.",
input: {
label: "Project Name",
placeholder: "My awesome project",
},
action: {
label: "Create",
onClick: async (projectName) => {
if (!projectName?.trim()) return
await createProject(projectName)
},
},
})
Input dialog with validation
dialogManager.input({
title: "Rename File",
description: "Enter a new name for this file.",
input: {
label: "Filename",
placeholder: "document.pdf",
defaultValue: currentFilename,
},
action: {
label: "Rename",
onClick: async (filename) => {
if (!filename?.trim()) {
throw new Error("Filename cannot be empty")
}
if (!/^[a-zA-Z0-9._-]+$/.test(filename)) {
throw new Error("Invalid filename format")
}
await renameFile(filename)
},
},
})
Custom dialog with form
function CreateUserForm({ onClose }: { onClose: () => void }) {
const [formData, setFormData] = useState({ name: "", email: "" })
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
await createUser(formData)
onClose()
}
return (
<form onSubmit={handleSubmit} className="space-y-4 p-6">
<h2 className="text-lg font-semibold">Create New User</h2>
<div>
<Label htmlFor="name">Name</Label>
<Input
id="name"
value={formData.name}
onChange={(e) =>
setFormData((prev) => ({ ...prev, name: e.target.value }))
}
/>
</div>
<div>
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
value={formData.email}
onChange={(e) =>
setFormData((prev) => ({ ...prev, email: e.target.value }))
}
/>
</div>
<div className="flex justify-end gap-2">
<Button type="button" variant="outline" onClick={onClose}>
Cancel
</Button>
<Button type="submit">Create User</Button>
</div>
</form>
)
}
// Usage
dialogManager.custom({
children: <CreateUserForm onClose={() => dialogManager.closeAll()} />,
})
Loading State
If you return a promise from the action, the dialog will show a loading state.
If the promise is rejected, the dialog will not be closed.
dialogManager.confirm({
title: "Delete Item",
description: "Are you sure you want to delete this item?",
action: {
label: "Delete",
variant: "destructive",
onClick: async () => {
await new Promise((resolve) => setTimeout(resolve, 1000))
throw new Error("Failed to delete item")
},
},
})
Build Your SaaS in Days, Not Months
NOW.TS is the Next.js 15 boilerplate with everything you need to launch your SaaS—auth, payments, database, and AI-ready infrastructure.
Learn more about NOW.TS