Shadcn Alert
Free shadcn/ui alert component for React — an inline message banner with an icon, title, and description. Default and destructive variants plus success/warning/info, actions, dismissible, and a full-width banner.
Installation
{
"registries": {
"@designrevision": "https://registry.designrevision.com/r/{name}.json"
}
}
Add to your existing components.json. Requires shadcn/ui v2.3+.
Packages
Props
variant
= "default"
"default" | "destructive"
Visual style. default for neutral messages, destructive for errors.
An inline alert (a message banner) — distinct from Alert Dialog (the modal). Compose <Alert> with <AlertTitle> and <AlertDescription>; drop a Lucide icon as the first child and the CSS grid lays it out automatically. variant is "default" or "destructive" (extend the cva for success/warning/info). It carries role="alert" so screen readers announce it.
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const alertVariants = cva(
"relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
{
variants: {
variant: {
default: "bg-card text-card-foreground",
destructive:
"text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90",
},
},
defaultVariants: {
variant: "default",
},
}
)
function Alert({
className,
variant,
...props
}: React.ComponentProps<"div"> & VariantProps<typeof alertVariants>) {
return (
<div
data-slot="alert"
role="alert"
className={cn(alertVariants({ variant }), className)}
{...props}
/>
)
}
function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="alert-title"
className={cn(
"col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight",
className
)}
{...props}
/>
)
}
function AlertDescription({
className,
...props
}: React.ComponentProps<"div">) {
return (
<div
data-slot="alert-description"
className={cn(
"text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed",
className
)}
{...props}
/>
)
}
export { Alert, AlertTitle, AlertDescription }
Examples
Default & destructive
The canonical alert — icon, title, and description in the two built-in variants.
Packages
Props
No props documented yet.
import { CircleAlertIcon, TerminalIcon } from "lucide-react"
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
export default function AlertDemo01() {
return (
<div className="w-full max-w-md space-y-4">
<Alert>
<TerminalIcon />
<AlertTitle>Heads up!</AlertTitle>
<AlertDescription>
You can add components to your app using the CLI.
</AlertDescription>
</Alert>
<Alert variant="destructive">
<CircleAlertIcon />
<AlertTitle>Error</AlertTitle>
<AlertDescription>
Your session has expired. Please log in again.
</AlertDescription>
</Alert>
</div>
)
}
Success / warning / info
Extra status colors built by overriding the border, text, and icon color.
Packages
Props
No props documented yet.
import { CircleCheckIcon, InfoIcon, TriangleAlertIcon } from "lucide-react"
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
export default function AlertVariants01() {
return (
<div className="w-full max-w-md space-y-4">
<Alert className="border-green-500/50 text-green-700 dark:text-green-400 [&>svg]:text-green-600">
<CircleCheckIcon />
<AlertTitle>Success</AlertTitle>
<AlertDescription className="text-green-700/80 dark:text-green-400/80">
Your changes have been saved.
</AlertDescription>
</Alert>
<Alert className="border-amber-500/50 text-amber-700 dark:text-amber-400 [&>svg]:text-amber-600">
<TriangleAlertIcon />
<AlertTitle>Warning</AlertTitle>
<AlertDescription className="text-amber-700/80 dark:text-amber-400/80">
Your trial ends in 3 days.
</AlertDescription>
</Alert>
<Alert className="border-blue-500/50 text-blue-700 dark:text-blue-400 [&>svg]:text-blue-600">
<InfoIcon />
<AlertTitle>Information</AlertTitle>
<AlertDescription className="text-blue-700/80 dark:text-blue-400/80">
A new version is available.
</AlertDescription>
</Alert>
</div>
)
}
Title-only & description-only
Minimal alerts — the icon column collapses automatically when there's no icon.
Packages
Props
No props documented yet.
import { CheckIcon } from "lucide-react"
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
export default function AlertSimple01() {
return (
<div className="w-full max-w-md space-y-4">
{/* Title only, with an icon */}
<Alert>
<CheckIcon />
<AlertTitle>Your changes have been saved.</AlertTitle>
</Alert>
{/* Description only, no icon — the grid collapses the icon column */}
<Alert>
<AlertDescription>
We use cookies to improve your experience.
</AlertDescription>
</Alert>
</div>
)
}
With actions
Trailing action buttons aligned under the content — the update/notice pattern.
Packages
Props
No props documented yet.
import { RocketIcon } from "lucide-react"
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
import { Button } from "@/components/ui/button"
export default function AlertAction01() {
return (
<Alert className="w-full max-w-md">
<RocketIcon />
<AlertTitle>Update available</AlertTitle>
<AlertDescription>
A new version is ready to install.
</AlertDescription>
<div className="col-start-2 mt-2 flex gap-2">
<Button size="sm">Update now</Button>
<Button size="sm" variant="ghost">
Later
</Button>
</div>
</Alert>
)
}
Dismissible
A closable alert — an X button toggles it with `useState`.
Packages
Props
No props documented yet.
"use client"
import * as React from "react"
import { InfoIcon, XIcon } from "lucide-react"
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
import { Button } from "@/components/ui/button"
export default function AlertDismissible01() {
const [open, setOpen] = React.useState(true)
if (!open) {
return (
<Button variant="outline" size="sm" onClick={() => setOpen(true)}>
Show alert
</Button>
)
}
return (
<Alert className="relative w-full max-w-md pr-12">
<InfoIcon />
<AlertTitle>New feature</AlertTitle>
<AlertDescription>
Dark mode is now available in settings.
</AlertDescription>
<Button
variant="ghost"
size="icon"
className="absolute top-2 right-2 size-7"
onClick={() => setOpen(false)}
>
<XIcon />
<span className="sr-only">Dismiss</span>
</Button>
</Alert>
)
}
Announcement banner
A full-width, high-emphasis banner — a colored Alert with an inline link.
Packages
Props
No props documented yet.
import { MegaphoneIcon } from "lucide-react"
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
export default function AlertBanner01() {
return (
<Alert className="bg-primary text-primary-foreground border-primary w-full [&>svg]:text-current">
<MegaphoneIcon />
<AlertTitle>Black Friday — 50% off all plans</AlertTitle>
<AlertDescription className="text-primary-foreground/90">
Offer ends Monday.{" "}
<a href="#" className="font-medium underline underline-offset-2">
Claim it now
</a>
.
</AlertDescription>
</Alert>
)
}
With a list
A destructive alert whose description holds a bulleted list — a form-error summary.
Packages
Props
No props documented yet.
import { CircleAlertIcon } from "lucide-react"
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
export default function AlertList01() {
return (
<Alert variant="destructive" className="w-full max-w-md">
<CircleAlertIcon />
<AlertTitle>Unable to submit your form</AlertTitle>
<AlertDescription>
<ul className="list-inside list-disc text-sm">
<li>Email is required</li>
<li>Password must be at least 8 characters</li>
<li>You must accept the terms</li>
</ul>
</AlertDescription>
</Alert>
)
}
The Shadcn Alert is an inline message banner — a bordered box with an optional icon, a title, and a description that surfaces a status or notice in the page flow. It ships default and destructive variants, lays out its icon automatically, and restyles easily for success, warning, and info. The examples below cover variants, icons, actions, a dismissible alert, and a full-width banner.
Alert vs Alert Dialog
These are two different components — don't mix them up:
- Alert (this page) — an inline message that lives in the layout. A banner, a form-error summary, a notice.
- Alert Dialog — a modal that interrupts the user to confirm or cancel a destructive action.
If you want a message in the page, use Alert. If you need a blocking confirm, use Alert Dialog.
Anatomy
Three parts, composed:
<Alert>
<TerminalIcon />
<AlertTitle>Heads up!</AlertTitle>
<AlertDescription>
You can add components to your app using the CLI.
</AlertDescription>
</Alert>
Drop a Lucide icon as the first child and the component's CSS grid detects it (has-[>svg]) and creates an icon column automatically. With no icon, that column collapses and the content spans the full width.
Variants
Two are built in:
<Alert variant="destructive">
<CircleAlertIcon />
<AlertTitle>Error</AlertTitle>
<AlertDescription>Your session has expired.</AlertDescription>
</Alert>
For success / warning / info, override the border, text, and icon color with a className (the Success / warning / info example shows green, amber, and blue). If you use them often, add them to the cva variants so variant="success" works directly.
Actions and dismissing
- Actions — add buttons under the content (aligned to the text column with
col-start-2) for "Update now / Later" style notices. - Dismissible — track an open state and render a corner close button (the Dismissible example uses
useState). For transient, stacking notifications instead, reach for a toast (Sonner).
Announcement banner
For a high-emphasis, full-width bar, give the Alert a colored background and an inline link — the Announcement banner example uses bg-primary text-primary-foreground for a promo or notice at the top of a page.
Accessibility
The Alert sets role="alert", so assistive tech announces its content as it appears — right for important, time-sensitive messages. For routine notices you can soften the urgency (e.g. role="status"). Keep the meaning in the title and description; decorative icons are not announced.