Alert
A callout for displaying important information. Built with Base UI and Tailwind CSS. Copy-paste ready.
Describe what can be done about it here.
import {
Alert,
AlertDescription,
AlertTitle,
} from "@/components/ui/alert";
export default function Particle() {
return (
<Alert>
<AlertTitle>Heads up!</AlertTitle>
<AlertDescription>
<p>Describe what can be done about it here.</p>
</AlertDescription>
</Alert>
);
}
Installation
pnpm dlx shadcn@latest add @cnippet/alert
Usage
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"<Alert>
<AlertTitle>Heads up!</AlertTitle>
<AlertDescription>
You can add components and dependencies to your app using the cli.
</AlertDescription>
</Alert>Examples
With Icon
Place any Lucide icon directly inside Alert before the title and description to reinforce the message type visually.
import { InfoIcon } from "lucide-react";
import {
Alert,
AlertDescription,
AlertTitle,
} from "@/components/ui/alert";
export default function Particle() {
return (
<Alert>
<InfoIcon />
<AlertTitle>Alert!</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
</Alert>
);
}
With Actions
Extends the icon alert with one or more action buttons in the footer — useful for alerts requiring a user decision.
import { InfoIcon } from "lucide-react";
import {
Alert,
AlertAction,
AlertDescription,
AlertTitle,
} from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
export default function Particle() {
return (
<Alert className="w-full">
<InfoIcon />
<AlertTitle>Security Update</AlertTitle>
<AlertDescription>Update your password and enable 2FA.</AlertDescription>
<AlertAction>
<Button size="xs" variant="ghost">
Dismiss
</Button>
<Button size="xs">Update</Button>
</AlertAction>
</Alert>
);
}
Info Alert
Uses the info variant with a blue color scheme to surface neutral information or tips.
import { InfoIcon } from "lucide-react";
import {
Alert,
AlertDescription,
AlertTitle,
} from "@/components/ui/alert";
export default function Particle() {
return (
<Alert variant="info">
<InfoIcon />
<AlertTitle>Info!</AlertTitle>
<AlertDescription>
This is an important message. Please read it carefully.
</AlertDescription>
</Alert>
);
}
Success Alert
Uses the success variant with a green color scheme to confirm a completed action or positive system state.
import { CircleCheckIcon } from "lucide-react";
import {
Alert,
AlertDescription,
AlertTitle,
} from "@/components/ui/alert";
export default function Particle() {
return (
<Alert variant="success">
<CircleCheckIcon />
<AlertTitle>Success!</AlertTitle>
<AlertDescription>
Everything is working as expected. You can continue with your task.
</AlertDescription>
</Alert>
);
}
Warning Alert
Uses the warning variant with an amber color scheme to flag a potential issue that requires attention.
import { TriangleAlertIcon } from "lucide-react";
import {
Alert,
AlertDescription,
AlertTitle,
} from "@/components/ui/alert";
export default function Particle() {
return (
<Alert variant="warning">
<TriangleAlertIcon />
<AlertTitle>Warning!</AlertTitle>
<AlertDescription>
Please check your settings. If the problem persists, contact support.
</AlertDescription>
</Alert>
);
}
Error Alert
Uses the destructive variant with a red color scheme to communicate an error or blocking problem.
import { CircleAlertIcon } from "lucide-react";
import {
Alert,
AlertDescription,
AlertTitle,
} from "@/components/ui/alert";
export default function Particle() {
return (
<Alert variant="error">
<CircleAlertIcon />
<AlertTitle>Error!</AlertTitle>
<AlertDescription>
Please try again. If the problem persists, contact support.
</AlertDescription>
</Alert>
);
}
Stacked in Frame
Multiple alerts of different severity levels stacked vertically inside a Frame container — a realistic notification panel layout.
import { AlertTriangleIcon, CircleCheckIcon } from "lucide-react";
import {
Alert,
AlertAction,
AlertDescription,
AlertTitle,
} from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import { Frame, FramePanel } from "@/components/ui/frame";
export function Pattern() {
return (
<div className="mx-auto mb-auto w-full max-w-lg">
<Frame>
<FramePanel className="p-0!">
<Alert
className="rounded-none border-0 shadow-none"
variant="success"
>
<CircleCheckIcon />
<AlertTitle>Deployment Successful</AlertTitle>
<AlertDescription>
Your application has been successfully deployed to the production
environment.
</AlertDescription>
</Alert>
</FramePanel>
<FramePanel className="p-0!">
<Alert
className="rounded-none border-0 shadow-none"
variant="warning"
>
<AlertTriangleIcon className="text-yellow-500" />
<AlertTitle>Resource Limit Reached</AlertTitle>
<AlertAction>
<Button size="xs">Verify</Button>
</AlertAction>
<AlertDescription>
Your current plan has reached its resource limits. Consider
upgrading to a higher tier.
</AlertDescription>
</Alert>
</FramePanel>
</Frame>
</div>
);
}
Actions in Frame
An alert with CTA buttons embedded inside a framed card, useful for onboarding banners or in-app upgrade prompts.
import { ShieldCheckIcon } from "lucide-react";
import {
Alert,
AlertAction,
AlertDescription,
AlertTitle,
} from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import { Frame, FramePanel } from "@/components/ui/frame";
export function Pattern() {
return (
<div className="mx-auto mb-auto w-full max-w-lg">
<Frame>
<FramePanel className="overflow-hidden p-0!">
<Alert className="border-0 shadow-none">
<ShieldCheckIcon className="text-emerald-500" />
<AlertTitle>Security Update</AlertTitle>
<AlertAction>
<Button size="xs" variant="outline">
Dismiss
</Button>
<Button size="xs">Update</Button>
</AlertAction>
<AlertDescription>
Update your password and enable 2FA to improve your account
security.
</AlertDescription>
</Alert>
</FramePanel>
</Frame>
</div>
);
}
Feature Discovery
A dismissible banner that introduces a new feature with a visual accent, a short description, and a "Learn more" link.
import { LightbulbIcon, XIcon } from "lucide-react";
import {
Alert,
AlertAction,
AlertDescription,
AlertTitle,
} from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import { Frame, FramePanel } from "@/components/ui/frame";
export function Pattern() {
return (
<div className="mx-auto mb-auto w-full max-w-lg">
<Frame>
<FramePanel className="overflow-hidden p-0!">
<Alert className="border-0 shadow-none" variant="info">
<LightbulbIcon />
<AlertTitle>New: Advanced Analytics</AlertTitle>
<AlertAction className="flex items-start justify-start">
<Button
className="-mt-1 -mr-2 size-7 p-0 text-muted-foreground hover:bg-transparent hover:text-foreground"
size="xs"
variant="ghost"
>
<XIcon className="size-3.5" />
</Button>
</AlertAction>
<AlertDescription>
We've just released a new dashboard for tracking your
team's performance.
<Button
className="mr-auto h-auto p-0 text-info underline"
size="sm"
variant="link"
>
Explore features
</Button>
</AlertDescription>
</Alert>
</FramePanel>
</Frame>
</div>
);
}
Announcement Banner
A full-width violet-tinted banner with a megaphone icon and a close button. Use it for product announcements or promotional messages at the top of a page.
"use client";
import { ArrowRightIcon, MegaphoneIcon, XIcon } from "lucide-react";
import { useState } from "react";
import {
Alert,
AlertAction,
AlertDescription,
AlertTitle,
} from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
export function Pattern() {
const [visible, setVisible] = useState(true);
if (!visible) return null;
return (
<div className="w-full max-w-2xl">
<Alert className="border-violet-200 bg-violet-50 dark:border-violet-800 dark:bg-violet-950/40">
<MegaphoneIcon className="text-violet-600 dark:text-violet-400" />
<AlertTitle className="text-violet-900 dark:text-violet-100">
Introducing Cnippet Pro
</AlertTitle>
<AlertAction className="flex items-start">
<Button
className="-mt-1 -mr-1 size-7 text-violet-500 hover:bg-violet-100 dark:hover:bg-violet-900"
onClick={() => setVisible(false)}
size="xs"
variant="ghost"
>
<XIcon className="size-3.5" />
</Button>
</AlertAction>
<AlertDescription className="text-violet-700 dark:text-violet-300">
Unlock premium components, templates, and priority support.{" "}
<Button
className="mr-auto h-auto p-0 text-violet-700 underline underline-offset-2 dark:text-violet-300"
size="sm"
variant="link"
>
Learn more
<ArrowRightIcon className="size-3" />
</Button>
</AlertDescription>
</Alert>
</div>
);
}
Cookie Consent
A bottom-anchored cookie banner with Decline and Accept All buttons. Clicking either option hides the alert, mirroring a real consent flow.
"use client";
import { CookieIcon } from "lucide-react";
import { useState } from "react";
import {
Alert,
AlertAction,
AlertDescription,
AlertTitle,
} from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
export function Pattern() {
const [dismissed, setDismissed] = useState(false);
if (dismissed) return null;
return (
<div className="w-full max-w-lg">
<Alert className="shadow-md">
<CookieIcon />
<AlertTitle>We use cookies</AlertTitle>
<AlertDescription className="inline-auto">
We use cookies to personalize content, analyze traffic, and improve
your experience. By continuing, you agree to our{" "}
<a
className="underline underline-offset-2 hover:text-foreground"
href="#"
>
cookie policy
</a>
.
</AlertDescription>
<AlertAction className="mt-1">
<Button
onClick={() => setDismissed(true)}
size="xs"
variant="outline"
>
Decline
</Button>
<Button onClick={() => setDismissed(true)} size="xs">
Accept All
</Button>
</AlertAction>
</Alert>
</div>
);
}
Storage Limit Warning
A warning-variant alert embedded in a Frame that shows current storage usage as a percentage and an inline progress bar, with an Upgrade CTA.
import { HardDriveIcon } from "lucide-react";
import {
Alert,
AlertAction,
AlertDescription,
AlertTitle,
} from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import { Frame, FramePanel } from "@/components/ui/frame";
export function Pattern() {
const used = 9.1;
const limit = 10;
const pct = Math.round((used / limit) * 100);
return (
<div className="mx-auto mb-auto w-full max-w-lg">
<Frame>
<FramePanel className="p-0!">
<Alert
className="rounded-none border-0 shadow-none"
variant="warning"
>
<HardDriveIcon className="text-yellow-500" />
<AlertTitle>Storage almost full</AlertTitle>
<AlertAction>
<Button size="xs">Upgrade</Button>
</AlertAction>
<AlertDescription>
<span>
You've used{" "}
<strong>
{used} GB of {limit} GB
</strong>{" "}
({pct}%).
</span>
<div className="mt-2 h-1.5 w-full overflow-hidden rounded-full bg-yellow-100 dark:bg-yellow-900/40">
<div
className="h-full rounded-full bg-yellow-500 transition-all"
style={{ width: `${pct}%` }}
/>
</div>
</AlertDescription>
</Alert>
</FramePanel>
</Frame>
</div>
);
}
Update Available
An info-variant alert that transforms into a success state after the user clicks "Update now". A simulated async delay with a loading label provides realistic feedback.
"use client";
import { DownloadIcon, PackageCheckIcon } from "lucide-react";
import { useState } from "react";
import {
Alert,
AlertAction,
AlertDescription,
AlertTitle,
} from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import { Frame, FramePanel } from "@/components/ui/frame";
export function Pattern() {
const [updating, setUpdating] = useState(false);
const [done, setDone] = useState(false);
const handleUpdate = () => {
setUpdating(true);
setTimeout(() => {
setUpdating(false);
setDone(true);
}, 2000);
};
return (
<div className="mx-auto mb-auto w-full max-w-lg">
<Frame>
<FramePanel className="p-0!">
<Alert
className="rounded-none border-0 shadow-none"
variant={done ? "success" : "info"}
>
{done ? <PackageCheckIcon /> : <DownloadIcon />}
<AlertTitle>
{done ? "You're up to date" : "Update available — v4.2.0"}
</AlertTitle>
{!done && (
<AlertAction>
<Button disabled={updating} onClick={handleUpdate} size="xs">
{updating ? "Updating…" : "Update now"}
</Button>
</AlertAction>
)}
<AlertDescription>
{done
? "cnippet@4.2.0 is now installed. Restart your dev server to apply the changes."
: "Includes performance improvements, 3 new components, and bug fixes."}
</AlertDescription>
</Alert>
</FramePanel>
</Frame>
</div>
);
}
Email Verification
An actionable alert prompting the user to verify their email address. The Resend button triggers a 60-second countdown before it becomes clickable again.
"use client";
import { MailIcon } from "lucide-react";
import { useEffect, useState } from "react";
import {
Alert,
AlertAction,
AlertDescription,
AlertTitle,
} from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
export function Pattern() {
const [sent, setSent] = useState(false);
const [countdown, setCountdown] = useState(0);
useEffect(() => {
if (countdown <= 0) return;
const t = setTimeout(() => setCountdown((c) => c - 1), 1000);
return () => clearTimeout(t);
}, [countdown]);
const handleResend = () => {
setSent(true);
setCountdown(60);
};
return (
<div className="w-full max-w-lg">
<Alert>
<MailIcon />
<AlertTitle>Verify your email address</AlertTitle>
<AlertAction>
<Button
disabled={countdown > 0}
onClick={handleResend}
size="xs"
variant="outline"
>
{countdown > 0 ? `Resend in ${countdown}s` : "Resend"}
</Button>
</AlertAction>
<AlertDescription>
{sent
? "A new verification email has been sent to your inbox."
: "We sent a confirmation link to hello@example.com. Check your inbox and click the link to activate your account."}
</AlertDescription>
</Alert>
</div>
);
}

