Alert
Inline alerts and page banners in four tones, with actions and dismiss.
$
pnpm dlx shadcn@latest add https://lodeui.com/r/alert.jsonScheduled maintenance
The dashboard will be read-only on Oct 12, 02:00–02:30 UTC.
Payment received
Your invoice for October is paid.
You've used 92% of your API quota
Card declined
Update your payment method to keep your workspace active.
components/examples/alert-demo.tsx
"use client";
import { Alert } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
export default function AlertDemo() {
return (
<div className="w-full max-w-lg space-y-3">
<Alert tone="info" title="Scheduled maintenance">The dashboard will be read-only on Oct 12, 02:00–02:30 UTC.</Alert>
<Alert tone="success" title="Payment received" dismissible>Your invoice for October is paid.</Alert>
<Alert tone="warning" title="You've used 92% of your API quota" action={<Button size="sm" variant="outline">Upgrade</Button>} />
<Alert tone="danger" title="Card declined" dismissible>Update your payment method to keep your workspace active.</Alert>
</div>
);
}When to use
- Messages about a page or section: trial ending, failed payment, maintenance.
- Full-width banners at the top of an app.
When not to use
- Short-lived confirmations: use a toast.
- Field errors: use Field's error.
Installation
$
pnpm dlx shadcn@latest add https://lodeui.com/r/alert.json1Install the dependencies
npm install motion lucide-react2Copy the source into your project
components/ui/alert.tsx"use client"; import * as React from "react"; import { AnimatePresence, motion } from "motion/react"; import { AlertTriangle, CheckCircle2, Info, OctagonAlert, X } from "lucide-react"; import { cn } from "@/lib/utils"; const tones = { info: { icon: <Info />, cls: "border-sky-500/30 bg-sky-500/6 [&>svg]:text-sky-500" }, success: { icon: <CheckCircle2 />, cls: "border-emerald-500/30 bg-emerald-500/6 [&>svg]:text-emerald-500" }, warning: { icon: <AlertTriangle />, cls: "border-amber-500/35 bg-amber-500/7 [&>svg]:text-amber-500" }, danger: { icon: <OctagonAlert />, cls: "border-destructive/35 bg-destructive/6 [&>svg]:text-destructive" }, neutral: { icon: <Info />, cls: "border-border bg-muted/40 [&>svg]:text-muted-foreground" }, }; export interface AlertProps { tone?: keyof typeof tones; title: React.ReactNode; children?: React.ReactNode; action?: React.ReactNode; /** Shows a close button; the alert animates out. */ dismissible?: boolean; onDismiss?: () => void; /** "inline" for content, "banner" for a full-width strip at the top of a page. */ variant?: "inline" | "banner"; className?: string; } export function Alert({ tone = "info", title, children, action, dismissible, onDismiss, variant = "inline", className }: AlertProps) { const [open, setOpen] = React.useState(true); const t = tones[tone]; return ( <AnimatePresence initial={false}> {open && ( <motion.div role={tone === "danger" || tone === "warning" ? "alert" : "status"} exit={{ opacity: 0, height: 0, marginTop: 0, marginBottom: 0 }} transition={{ duration: 0.2 }} className={cn( "relative flex items-start gap-3 overflow-hidden border text-sm [&>svg]:mt-0.5 [&>svg]:size-4 [&>svg]:shrink-0", variant === "inline" ? "rounded-lg p-3.5" : "border-x-0 px-4 py-2.5 sm:items-center", t.cls, dismissible && "pr-10", className, )} > {t.icon} <div className={cn("min-w-0 flex-1", variant === "banner" && "sm:flex sm:items-center sm:gap-2")}> <p className="font-medium">{title}</p> {children && <div className={cn("text-muted-foreground", variant === "inline" && "mt-0.5")}>{children}</div>} </div> {action && <div className="shrink-0">{action}</div>} {dismissible && ( <button type="button" aria-label="Dismiss" onClick={() => { setOpen(false); onDismiss?.(); }} className="absolute right-2 top-2.5 grid size-6 place-items-center rounded text-muted-foreground hover:bg-black/5 hover:text-foreground dark:hover:bg-white/10" > <X className="size-3.5" /> </button> )} </motion.div> )} </AnimatePresence> ); }
Usage
Import it from @/components/ui/alert after installing.
example.tsx
import { Alert } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
export function PaymentFailed() {
return (
<Alert tone="danger" title="Your last payment failed" action={<Button size="sm">Update card</Button>} dismissible>
We'll retry in 3 days. Update your card to avoid interruption.
</Alert>
);
}API reference
Alert
An icon, title, body and optional action, inline or as a banner.
| Prop | Type | Default | Description |
|---|---|---|---|
| tone | "info" | "success" | "warning" | "danger" | "neutral" | "info" | Color and icon. |
| title | ReactNode | – | One-line summary. |
| children | ReactNode | – | Details. |
| action | ReactNode | – | A button or link. |
| dismissible / onDismiss | boolean / () => void | – | Close button; the alert animates out. |
| variant | "inline" | "banner" | "inline" | Card or full-width strip. |
Keyboard interactions
| Keys | Action |
|---|---|
| Tab | Reach the action and close button |
Accessibility
- The icon is decorative; the title states the message.
- The close button is labelled.
Motion
- Dismissing collapses the height and fades out.
Responsive behavior
- The action moves under the text on narrow screens.
Performance
- Static until dismissed.
Notes for AI
- Use tone="danger" only when something is broken or blocked.
This page as Markdown, for assistants and coding agents:
/components/alert/markdownThe full library index for assistants is at /llms.txt.
Lode222 doc pagesllms.txt