ScrollX UI
uialert-dialogsource: ok · hit
Alert Dialog
A modal dialog used to convey critical information and require a user response before proceeding..
npx shadcn add "https://www.scrollxui.dev/registry/alert-dialog.json"free
Interaction
modal
Tags auto-generated by rules on 9/24/2026 — empty means no evidence, not lack of support.
Dependencies
Bundle weight · mediumui-primitives@radix-ui/react-alert-dialog@radix-ui/react-slot
animationmotion
iconslucide-react
Registry dependencies
@scrollxui/button
Files3 · source cached 10/8/2026, 2:54:50 PM
components/ui/alert-dialog.tsx
'use client';
import * as React from 'react';
import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
import { motion } from 'motion/react';
import { cn } from '@/lib/utils';
import { buttonVariants } from '@/components/ui/button';
const AlertDialog = AlertDialogPrimitive.Root;
const AlertDialogTrigger = AlertDialogPrimitive.Trigger;
const AlertDialogPortal = AlertDialogPrimitive.Portal;
const AlertDialogOverlay = React.forwardRef<
React.ComponentRef<typeof AlertDialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Overlay
ref={ref}
className={cn(
'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
className,
)}
{...props}
/>
));
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
const AlertDialogContent = React.forwardRef<
React.ComponentRef<typeof AlertDialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
>(({ className, children }, _ref) => {
const contentRef = React.useRef<HTMLDivElement>(null);
const [shakeKey, setShakeKey] = React.useState(0);
React.useEffect(() => {
function handleOutsideClick(event: MouseEvent | TouchEvent) {
const node = contentRef.current;
const target = event.target as Node | null;
if (node && target && !node.contains(target)) {
setShakeKey((k) => k + 1);
}
}
document.addEventListener('mousedown', handleOutsideClick);
document.addEventListener('touchstart', handleOutsideClick);
return () => {
document.removeEventListener('mousedown', handleOutsideClick);
document.removeEventListener('touchstart', handleOutsideClick);
};
}, []);
return (
<AlertDialogPortal>
<AlertDialogOverlay />
<AlertDialogPrimitive.Content asChild>
<div className='fixed left-1/2 top-1/2 z-50 w-full max-w-lg -translate-x-1/2 -translate-y-1/2 sm:rounded-lg'>
<motion.div
key={shakeKey}
ref={contentRef}
animate={{ x: [0, -10, 10, -8, 8, -4, 4, 0] }}
transition={{ duration: 0.5, ease: 'easeInOut' }}
className={cn(
'grid gap-4 border bg-background p-6 shadow-lg',
className,
)}
>
{children}
</motion.div>
</div>
</AlertDialogPrimitive.Content>
</AlertDialogPortal>
);
});
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
const AlertDialogHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
'flex flex-col space-y-2 text-center sm:text-left',
className,
)}
{...props}
/>
);
AlertDialogHeader.displayName = 'AlertDialogHeader';
const AlertDialogFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
className,
)}
{...props}
/>
);
AlertDialogFooter.displayName = 'AlertDialogFooter';
const AlertDialogTitle = React.forwardRef<
React.ComponentRef<typeof AlertDialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Title
ref={ref}
className={cn('text-lg font-semibold', className)}
{...props}
/>
));
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
const AlertDialogDescription = React.forwardRef<
React.ComponentRef<typeof AlertDialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Description
ref={ref}
className={cn('text-sm text-muted-foreground', className)}
{...props}
/>
));
AlertDialogDescription.displayName =
AlertDialogPrimitive.Description.displayName;
const AlertDialogAction = React.forwardRef<
React.ComponentRef<typeof AlertDialogPrimitive.Action>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
>(({ className, children, ...props }, ref) => (
<AlertDialogPrimitive.Action asChild ref={ref} {...props}>
<motion.button
className={cn(
buttonVariants(),
'bg-linear-to-r from-blue-500 via-purple-500 to-pink-500 text-white',
className,
)}
style={{ perspective: 1000 }}
whileHover={{
rotateX: 25,
rotateY: 10,
translateZ: 100,
scale: 1.1,
boxShadow: '0px 20px 50px rgba(0, 102, 255, 0.4)',
}}
transition={{ type: 'spring', stiffness: 150, damping: 10 }}
>
{children}
</motion.button>
</AlertDialogPrimitive.Action>
));
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
const AlertDialogCancel = React.forwardRef<
React.ComponentRef<typeof AlertDialogPrimitive.Cancel>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Cancel
ref={ref}
className={cn(
buttonVariants({ variant: 'outline' }),
'mt-2 sm:mt-0',
className,
)}
{...props}
/>
));
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
export {
AlertDialog,
AlertDialogPortal,
AlertDialogOverlay,
AlertDialogTrigger,
AlertDialogContent,
AlertDialogHeader,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogDescription,
AlertDialogAction,
AlertDialogCancel,
};
components/ui/button.tsx
import * as React from 'react';
import { Slot } from '@radix-ui/react-slot';
import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from '@/lib/utils';
const buttonVariants = cva(
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
{
variants: {
variant: {
default:
'bg-primary text-primary-foreground shadow-sm hover:bg-primary/90',
destructive:
'bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90',
outline:
'border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground',
secondary:
'bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80',
ghost: 'hover:bg-accent hover:text-accent-foreground',
link: 'text-primary underline-offset-4 hover:underline',
success: 'bg-green-600 text-white hover:bg-green-700',
warning: 'bg-yellow-500 text-black hover:bg-yellow-600',
info: 'bg-blue-500 text-white hover:bg-blue-600',
dark: 'bg-gray-800 text-white hover:bg-gray-700',
light: 'bg-gray-100 text-gray-800 hover:bg-gray-200',
gradient:
'bg-linear-to-r from-indigo-500 via-purple-500 to-pink-500 text-white hover:opacity-90',
glass:
'bg-white/10 backdrop-blur-md text-white border border-white/20 hover:bg-white/20',
},
size: {
default: 'h-9 px-4 py-2',
sm: 'h-8 rounded-md px-3 text-xs',
lg: 'h-10 rounded-md px-8',
icon: 'h-9 w-9',
},
},
defaultVariants: {
variant: 'default',
size: 'default',
},
},
);
export interface ButtonProps
extends
React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean;
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : 'button';
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
);
},
);
Button.displayName = 'Button';
export { Button, buttonVariants };
lib/utils.ts
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}