UIUI
Alert
A versatile alert component for displaying important messages, notifications, and status updates.
Code Review Ready
Your pull request is ready for code review by the team.
Feature Unlocked
Congratulations! You've unlocked premium features.
Performance Improved
Your application performance has increased by 40% this month.
Security Alert
We detected unusual login activity. Please verify your account.
Meeting Reminder
Your team standup meeting starts in 15 minutes.
<div className="space-y-4">
<Alert icon={Code} variant="info" title="Code Review Ready">
Your pull request is ready for code review by the team.
</Alert>
<Alert icon={Sparkles} variant="success" title="Feature Unlocked">
Congratulations! You've unlocked premium features.
</Alert>
<Alert icon={TrendingUp} variant="info" title="Performance Improved">
Your application performance has increased by 40% this month.
</Alert>
<Alert icon={Lock} variant="warning" title="Security Alert">
We detected unusual login activity. Please verify your account.
</Alert>
<Alert icon={Calendar} variant="default" title="Meeting Reminder">
Your team standup meeting starts in 15 minutes.
</Alert>
</div>
Installation
Install following dependencies:
npm install class-variance-authority lucide-react motion
Copy and paste the following code into your project.
"use client";
import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
import { type LucideIcon, X } from "lucide-react";
import { motion, AnimatePresence } from "motion/react";
const alertVariants = cva(
"relative w-full rounded-lg border p-4 text-sm transition-colors ",
{
variants: {
variant: {
default:
"border-border bg-card text-card-foreground",
destructive:
"border-destructive bg-destructive/10 text-destructive [&>svg]:text-destructive",
warning:
"border-amber-200 bg-amber-50 text-amber-800 dark:border-amber-700 dark:bg-amber-950/30 dark:text-amber-200 [&>svg]:text-amber-600 dark:[&>svg]:text-amber-400",
success:
"border-green-200 bg-green-50 text-green-800 dark:border-green-700 dark:bg-green-950/30 dark:text-green-200 [&>svg]:text-green-600 dark:[&>svg]:text-green-400",
info: "border-blue-200 bg-blue-50 text-blue-800 dark:border-blue-700 dark:bg-blue-950/30 dark:text-blue-200 [&>svg]:text-blue-600 dark:[&>svg]:text-blue-400",
},
},
defaultVariants: {
variant: "default",
},
}
);
export interface AlertProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof alertVariants> {
icon?: LucideIcon;
title?: string;
dismissible?: boolean;
onDismiss?: () => void;
}
const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
(
{
className,
variant,
icon: Icon,
title,
dismissible,
onDismiss,
children,
...props
},
ref
) => {
const [isVisible, setIsVisible] = React.useState(true);
const handleDismiss = () => {
setIsVisible(false);
setTimeout(() => {
onDismiss?.();
}, 150); // Match the exit animation duration
};
// Extract motion-conflicting props
const {
onDrag,
onDragStart,
onDragEnd,
onAnimationStart,
onAnimationEnd,
onAnimationIteration,
onTransitionEnd,
...motionProps
} = props;
return (
<AnimatePresence>
{isVisible && (
<motion.div
ref={ref}
className={cn(alertVariants({ variant }), className)}
initial={{ opacity: 0, y: -10, scale: 0.95 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: -10, scale: 0.95 }}
transition={{ duration: 0.15, ease: "easeOut" }}
role="alert"
{...motionProps}
>
<div className="flex">
{Icon && (
<div className="flex-shrink-0">
<Icon className="h-4 w-4 mt-0.5" />
</div>
)}
<div className={cn("flex-1", Icon && "ml-3")}>
{title && <h3 className="text-sm font-medium mb-1">{title}</h3>}
<div
className={cn("text-sm", title && "text-muted-foreground")}
>
{children}
</div>
</div>
{dismissible && (
<div className="flex-shrink-0 ml-3">
<button
type="button"
className="inline-flex rounded-md p-1.5 transition-colors hover:bg-black/5 dark:hover:bg-white/5 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-ring"
onClick={handleDismiss}
aria-label="Dismiss alert"
>
<X className="h-4 w-4" />
</button>
</div>
)}
</div>
</motion.div>
)}
</AnimatePresence>
);
}
);
Alert.displayName = "Alert";
export { Alert, alertVariants };
npx hextaui@latest add alert
Usage
import { Alert } from "@/components/ui/alert";
<div className="space-y-4">
<Alert icon={Code} variant="info" title="Code Review Ready">
Your pull request is ready for code review by the team.
</Alert>
<Alert icon={Sparkles} variant="success" title="Feature Unlocked">
Congratulations! You've unlocked premium features.
</Alert>
<Alert icon={TrendingUp} variant="info" title="Performance Improved">
Your application performance has increased by 40% this month.
</Alert>
<Alert icon={Lock} variant="warning" title="Security Alert">
We detected unusual login activity. Please verify your account.
</Alert>
<Alert icon={Calendar} variant="default" title="Meeting Reminder">
Your team standup meeting starts in 15 minutes.
</Alert>
</div>
Props
Alert Props
Prop | Type | Default |
---|---|---|
variant? | "default" | "destructive" | "warning" | "success" | "info" | "default" |
icon? | LucideIcon | undefined |
title? | string | undefined |
dismissible? | boolean | false |
onDismiss? | () => void | undefined |
className? | string | undefined |
children? | ReactNode | undefined |
Edit on GitHub
Last updated on