Build websites 10x faster with HextaUI Blocks — Learn more
UI/UI

Alert

A versatile alert component for displaying important messages, notifications, and status updates.

<div className="space-y-4">
  <Alert>This is a basic alert message.</Alert>
  <Alert variant="destructive">
    Something went wrong. Please try again.
  </Alert>
  <Alert variant="warning">This action cannot be undone.</Alert>
  <Alert variant="success">Your changes have been saved.</Alert>
  <Alert variant="info">New features are now available.</Alert>
</div>

Installation

Install following dependencies:

npm install class-variance-authority lucide-react motion
pnpm add class-variance-authority lucide-react motion
yarn add class-variance-authority lucide-react motion
bun add class-variance-authority lucide-react motion

Copy and paste the following code into your project.

components/ui/alert.tsx
"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 shadow-sm/2",
  {
    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
pnpm dlx hextaui@latest add alert
yarn dlx hextaui@latest add alert
bun x hextaui@latest add alert

Usage

import { Alert } from "@/components/ui/alert";
import { Database, Rocket } from "lucide-react";

Basic Alert

<Alert variant="default">This is a default alert.</Alert>
<Alert variant="destructive">This is a destructive alert.</Alert>
<Alert variant="warning">This is a warning alert.</Alert>
<Alert variant="success">This is a success alert.</Alert>
<Alert variant="info">This is an info alert.</Alert>

Alert with Icons

<Alert icon={Database} variant="warning" title="Database Alert">
  This uses a Lucide icon component for maximum flexibility.
</Alert>

Examples

Variants

<div className="space-y-4">
  <Alert>
     This is a basic alert message.
  </Alert>
  <Alert variant="destructive">
    Something went wrong. Please try again.
  </Alert>
  <Alert variant="warning">
    This action cannot be undone.
  </Alert>
  <Alert variant="success">
    Your changes have been saved.
  </Alert>
  <Alert variant="info">
    New features are now available.
  </Alert>
</div>

With Titles

<div className="space-y-4">
  <Alert title="System Update">
    A new version of the application is available. Please restart to apply
    updates.
  </Alert>
  <Alert variant="destructive" title="Connection Failed">
    Unable to connect to the server. Please check your internet connection.
  </Alert>
  <Alert variant="warning" title="Data Loss Warning">
    You have unsaved changes. Leaving this page will discard your work.
  </Alert>
  <Alert variant="success" title="Upload Complete">
    Your files have been successfully uploaded to the cloud storage.
  </Alert>
  <Alert variant="info" title="Feature Preview">
    Try out our new dashboard features in beta mode.
  </Alert>
</div>

With Icons

import { 
  Info,
  CheckCircle,
  AlertTriangle,
  X,
  Wifi,
  Database,
  Rocket,
  Coffee,
} from "lucide-react";

<div className="space-y-4">
  {/* Using predefined icon names */}
  <Alert icon={Info} variant="info" title="New Features Available">
    We've added new collaboration tools to help you work better with your
    team.
  </Alert>
  <Alert icon={CheckCircle} variant="success" title="Payment Successful">
    Your subscription has been renewed for another year.
  </Alert>
  <Alert icon={AlertTriangle} variant="warning" title="Storage Almost Full">
    You've used 95% of your storage space. Consider upgrading your plan.
  </Alert>
  <Alert icon={X} variant="destructive" title="Action Failed">
    Could not complete the requested action. Please try again later.
  </Alert>

  {/* Using custom icon components */}
  <Alert icon={Wifi} variant="info" title="Network Connected">
    You are now connected to the secure network.
  </Alert>
  <Alert icon={Database} variant="warning" title="Database Backup Required">
    It's been 7 days since your last backup. Consider backing up your data.
  </Alert>
  <Alert icon={Rocket} variant="success" title="Deployment Successful">
    Your application has been deployed to production successfully.
  </Alert>
  <Alert icon={Coffee} variant="default" title="Break Time">
    You've been coding for 2 hours. Time for a coffee break!
  </Alert>
</div>

With Custom Icons

import { Code, Sparkles, TrendingUp, Lock, Calendar } from "lucide-react";

<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>

Dismissible Alerts

import { Bell, Trophy, HardDrive, Heart } from "lucide-react";

const handleDismiss = (message: string) => {
  console.log(message);
};

<div className="space-y-4">
  <Alert
    icon={Bell}
    variant="info"
    title="Notification"
    dismissible
    onDismiss={() => handleDismiss("Alert dismissed")}
  >
    You have 3 new messages in your inbox.
  </Alert>
  <Alert
    icon={Trophy}
    variant="success"
    title="Achievement Unlocked"
    dismissible
    onDismiss={() => handleDismiss("Achievement dismissed")}
  >
    Congratulations! You've completed 100 tasks this month.
  </Alert>
  <Alert
    icon={HardDrive}
    variant="warning"
    title="Storage Warning"
    dismissible
    onDismiss={() => handleDismiss("Storage warning dismissed")}
  >
    Your storage is almost full. Consider upgrading your plan.
  </Alert>

  {/* Custom icons with dismissible */}
  <Alert
    icon={Heart}
    variant="success"
    title="Thank You!"
    dismissible
    onDismiss={() => handleDismiss("Thank you dismissed")}
  >
    Thank you for being an awesome user! Your feedback helps us improve.
  </Alert>
</div>

Custom Styling

<div className="space-y-4">
  <Alert className="rounded-xl border-2">
    Custom border radius styling.
  </Alert>
  <Alert variant="info" className="border-dashed">
    Alert with dashed border style.
  </Alert>
  <Alert variant="success" className="shadow-lg">
    Alert with enhanced shadow.
  </Alert>
  <Alert className="bg-gradient-to-r from-purple-50 to-pink-50 border-purple-200 text-purple-800 dark:from-purple-950/20 dark:to-pink-950/20 dark:border-purple-800 dark:text-purple-200">
    Custom gradient styling.
  </Alert>
</div>

Real-world Examples

System Status

Account Security

Billing Information

import { Server, Shield, CreditCard } from "lucide-react";

<div className="space-y-4">
  <div className="space-y-2">
    <h4 className="text-sm font-medium">System Status</h4>
    <Alert icon={Server} variant="success" title="All Systems Operational">
      All services are running normally. Last updated 2 minutes ago.
    </Alert>
  </div>

  <div className="space-y-2">
    <h4 className="text-sm font-medium">Account Security</h4>
    <Alert icon={Shield} variant="warning" title="Password Expiring Soon">
      Your password will expire in 3 days. Update it now to maintain account security.
    </Alert>
  </div>

  <div className="space-y-2">
    <h4 className="text-sm font-medium">Billing Information</h4>
    <Alert icon={CreditCard} variant="destructive" title="Payment Method Required">
      Your trial ends in 2 days. Add a payment method to continue using our services.
    </Alert>
  </div>
</div>

Alert Sizes

<div className="space-y-4">
  <Alert className="text-xs p-3">Compact alert for minimal space.</Alert>
  <Alert>Standard size for most use cases.</Alert>
  <Alert className="text-base p-5">
    Prominent alert for important messages.
  </Alert>
</div>

Props

Alert Props

PropTypeDefault
children?
ReactNode
undefined
className?
string
undefined
onDismiss?
() => void
undefined
dismissible?
boolean
false
title?
string
undefined
icon?
LucideIcon
undefined
variant?
"default" | "destructive" | "warning" | "success" | "info"
"default"
Edit on GitHub

Last updated on