Dialog
Modal primitive for focused tasks and confirmation flows.
npx shadcn@latest add @aavya/ui-dialog
One-time setup — add the @aavya registry to your components.json so branded dependencies resolve to Aavya (not stock shadcn):
"registries": { "@aavya": "https://registry-dev.aavya.com/r/{name}.json" }Or install by full URL: npx shadcn@latest add https://registry-dev.aavya.com/r/ui-dialog.json
| Part | Prop | Type | Default |
|---|---|---|---|
| DialogContent | showCloseButton? | boolean | true |
Dialog forwards remaining props to DialogPrimitive.Root props.
Do
- Use a Dialog for a focused task that must be finished or dismissed before continuing.
- Use Alert Dialog (not Dialog) for destructive confirmations.
- Always render a DialogTitle (visually hidden if your design omits it).
Don’t
- Don't nest a Dialog inside a Dialog — restructure the flow into steps.
- Don't put long, scrolling content in a Dialog — use a Sheet or a dedicated page.
- Don't remove the close affordance; users need an obvious exit.
Role
dialog + aria-modal (handled by Radix).
Keyboard
Esc closes; focus is trapped inside; Tab/Shift+Tab wrap. (handled)
Screen reader
Must have an accessible title — render DialogTitle (wrap in a visually-hidden element if the design omits it), or screen readers announce nothing useful. You provide this.
Focus
Focus moves into the Dialog on open and returns to the trigger on close. (handled — don't override without reason)
Gotcha
Radix logs a warning when DialogTitle is missing; treat that warning as a bug, not noise.
import { Dialog } from '@/components/ui/dialog'
export default function Example() {
return (
<div className="p-6">
<Dialog />
</div>
)
}
'use client'
import * as React from 'react'
import * as DialogPrimitive from '@radix-ui/react-dialog'
import { XIcon } from 'lucide-react'
import { cn } from '@/lib/utils'
function Dialog({ ...props }: React.ComponentProps<typeof DialogPrimitive.Root>) {
return <DialogPrimitive.Root data-slot='dialog' {...props} />
}
function DialogTrigger({ ...props }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
return <DialogPrimitive.Trigger data-slot='dialog-trigger' {...props} />
}
function DialogPortal({ ...props }: React.ComponentProps<typeof DialogPrimitive.Portal>) {
return <DialogPrimitive.Portal data-slot='dialog-portal' {...props} />
}
function DialogClose({ ...props }: React.ComponentProps<typeof DialogPrimitive.Close>) {
return <DialogPrimitive.Close data-slot='dialog-close' {...props} />
}
function DialogOverlay({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
return (
<DialogPrimitive.Overlay
data-slot='dialog-overlay'
className={cn(
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50',
className
)}
{...props}
/>
)
}
function DialogContent({
className,
children,
showCloseButton = true,
...props
}: React.ComponentProps<typeof DialogPrimitive.Content> & {
showCl