Loading…
Loading…
Displays an important message to attract the user's attention without interrupting workflow.
The Alert (also called a banner, callout, notification banner, or inline notification) is a feedback component that displays an important message to the user without interrupting their workflow. Unlike a Dialog (which blocks interaction) or a Toast (which auto-dismisses), an alert is persistent, inline, and non-modal — it sits within the page content and stays visible until the user addresses it or the condition changes.
Alerts communicate status: success after an action, a warning about something that needs attention, an error that requires correction, or informational context that helps the user understand their situation. They're the "yellow sticky note on the monitor" of the digital world — visible, persistent, but not blocking.
When to use an Alert:
When NOT to use an Alert:
Alert vs. Toast decision: If the message is the result of a user action and can be missed without consequence, use a Toast. If the message describes a state the user needs to be aware of (and should see even if they weren't looking when it appeared), use an Alert.
Style your alert's border-radius with the Border Radius Generator and choose semantically appropriate color palettes with the Color Palette Generator. Always verify text contrast with the Contrast Checker.
| Variant | Color | Icon | Purpose |
|---|---|---|---|
| Info | Blue | ℹ️ (information circle) | Neutral information, tips, context. No urgency. |
| Success | Green | ✓ (checkmark circle) | Confirmation that an action completed successfully. |
| Warning | Yellow/Amber | ⚠️ (triangle exclamation) | Something needs attention but isn't blocking. |
| Error | Red | ✕ (X circle) or ❗ | Something went wrong. Action may be required. |
| Variant | Description |
|---|---|
| Filled | Solid background color (light tint of the semantic color). High visibility. |
| Outlined | White/transparent background with a colored left border (4px). Subtle but clear. |
| Soft | Very light tinted background with matching text color. Minimal visual weight. |
| Banner | Full-width, typically at the top of the page or content area. No border-radius. |
| Inline | Sits within the content flow. Has border-radius. Standard width. |
| Variant | Description |
|---|---|
| Simple | Icon + single line of text |
| With title | Icon + bold title + description text |
| With actions | Icon + text + action buttons or links ("Retry", "Dismiss", "Learn more") |
| With list | Icon + title + bulleted list of items (e.g., multiple form errors) |
| Dismissible | Includes a close (✕) button to remove the alert |
| Size | Padding | Font Size | Use Case |
|---|---|---|---|
| Small | 8px 12px | 13px | Inline field-level messages, compact UIs |
| Medium | 12px 16px | 14px | Default page-level alerts |
| Large | 16px 20px | 16px | Full-width banners, critical system alerts |
| Property | Type | Default | Description |
|---|---|---|---|
variant | 'info' | 'success' | 'warning' | 'error' | 'info' | Semantic variant controlling color and icon |
title | string | — | Bold heading text |
children | ReactNode | — | Alert body content |
icon | ReactNode | false | Auto (based on variant) | Custom icon. Set false to hide. |
dismissible | boolean | false | Shows a close button |
onDismiss | () => void | — | Callback when dismissed |
actions | ReactNode | — | Action buttons or links rendered in the alert footer |
role | 'alert' | 'status' | 'none' | 'status' | ARIA role. Use 'alert' for urgent messages, 'status' for informational. |
| Token Category | Token Example | Alert Usage |
|---|---|---|
| Color – Info Background | --color-info-50 | Info variant background |
| Color – Info Border | --color-info-200 | Info variant left border |
| Color – Info Icon | --color-info-600 | Info icon color |
| Color – Info Text | --color-info-800 | Info title color |
| Color – Success | --color-success-50 / -200 / -600 / -800 | Success variant tokens |
| Color – Warning | --color-warning-50 / -200 / -600 / -800 | Warning variant tokens |
| Color – Error | --color-error-50 / -200 / -600 / -800 | Error variant tokens |
| Border Radius | --radius-md (8px) or --radius-lg (12px) | Alert container corners. Preview with Border Radius Generator. |
| Border – Left Accent | 4px solid --color-[variant]-500 | Outlined variant left border |
| Spacing | --space-3 (12px), --space-4 (16px) | Internal padding |
| Spacing – Gap | --space-3 (12px) | Gap between icon, text, and actions |
| Typography – Title | --font-size-sm, --font-weight-semibold | Alert title |
| Typography – Body | --font-size-sm, --font-weight-normal | Alert description |
Use the Color Palette Generator to generate consistent semantic color scales for all four variants.
| State | Behavior |
|---|---|
| Visible | Alert is displayed inline in the content flow. Content before and after adjusts. |
| Entering | Fade in + slide down (optional). 200ms ease-out. |
| Dismissing | Fade out + slide up. On completion, the alert is removed from the DOM (not just hidden). Content below shifts up. |
| Dismissed | Alert is removed. If server-driven, the dismissal state may be persisted. |
| Context | Behavior |
|---|---|
| Page-level | Alert appears at the top of the content area, below the header. Full width of the content column. |
| Section-level | Alert appears within a specific section (form, card, panel). Scoped to that section's width. |
| Banner | Full viewport width, fixed or sticky at the top of the page. Used for system announcements. |
| Form error summary | Special alert at the top of a form listing all validation errors. Each error links to its field. |
Alerts that appear dynamically (after an API call, form submission, or system event) should be announced to screen readers. This is where role="alert" or role="status" becomes critical:
role="alert": Assertive. Screen readers interrupt whatever they're reading to announce the alert. Use for errors and urgent warnings.role="status": Polite. Screen readers announce it after finishing the current sentence. Use for success messages and informational updates.| Criterion | Level | Requirement |
|---|---|---|
| SC 1.4.1 Use of Color | A | Don't rely on color alone to convey the alert type. Include an icon (info, warning, error, success) alongside the color. |
| SC 1.4.3 Contrast (Minimum) | AA | Alert text must have 4.5:1 contrast against the alert background. This is frequently failed — dark text on a light tint needs careful calibration. Use Contrast Checker for every variant. |
| SC 1.4.11 Non-text Contrast | AA | Icons and borders: 3:1 against adjacent background. |
| SC 4.1.3 Status Messages | AA | Dynamic alerts must be announced to screen readers without receiving focus. Use role="alert" or role="status". |
| SC 2.2.1 Timing Adjustable | A | If the alert auto-dismisses, users must be able to extend the time or the alert must be available elsewhere. Consider making alerts persistent by default. |
For dynamically injected alerts:
<!-- Error: assertive announcement -->
<div role="alert">
<strong>Error:</strong> Unable to save your changes. Please try again.
</div>
<!-- Success: polite announcement -->
<div role="status">
Your profile has been updated successfully.
</div>
For alerts present on page load:
<!-- No role needed — content is in the natural reading flow -->
<div class="alert alert-info">
<p>This feature is currently in beta.</p>
</div>
aria-label="Dismiss" or aria-label="Close alert"aria-live regionThis is the biggest accessibility pitfall with alerts. Typical failures:
| Variant | Common Failure | Fix |
|---|---|---|
| Success | Dark green text on light green bg fails 4.5:1 | Use --color-success-800 on --color-success-50 — verify exact values |
| Warning | Orange text on yellow bg almost always fails | Use dark amber or near-black text on light yellow |
| Info | Light blue text on light blue bg | Use --color-info-800 for text, not --color-info-500 |
| Error | Usually passes — red on light pink has inherently higher contrast | Still verify |
Always test every variant in both light and dark mode. The Contrast Checker supports both.
For comprehensive patterns, see our WCAG Practical Guide and ARIA Attributes Guide.
<!-- Info Alert -->
<div class="alert alert-info" role="status">
<svg class="alert-icon" aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0Zm-7-4a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM9 9a.75.75 0 0 0 0 1.5h.25v2.75a.75.75 0 0 0 1.5 0V10A.75.75 0 0 0 10 9H9Z" clip-rule="evenodd"/>
</svg>
<div class="alert-content">
<p class="alert-title">New feature available</p>
<p class="alert-description">Dark mode is now available in settings. <a href="/settings">Try it out</a>.</p>
</div>
</div>
<!-- Error Alert with dismiss -->
<div class="alert alert-error" role="alert">
<svg class="alert-icon" aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16ZM8.28 7.22a.75.75 0 0 0-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 1 0 1.06 1.06L10 11.06l1.72 1.72a.75.75 0 1 0 1.06-1.06L11.06 10l1.72-1.72a.75.75 0 0 0-1.06-1.06L10 8.94 8.28 7.22Z" clip-rule="evenodd"/>
</svg>
<div class="alert-content">
<p class="alert-title">Unable to save changes</p>
<p class="alert-description">There was a network error. Please check your connection and try again.</p>
</div>
<button type="button" class="alert-dismiss" aria-label="Dismiss alert">
<svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="currentColor">
<path d="M6.28 5.22a.75.75 0 0 0-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 1 0 1.06 1.06L10 11.06l3.72 3.72a.75.75 0 1 0 1.06-1.06L11.06 10l3.72-3.72a.75.75 0 0 0-1.06-1.06L10 8.94 6.28 5.22Z"/>
</svg>
</button>
</div>
<!-- Form Error Summary Alert -->
<div class="alert alert-error" role="alert">
<svg class="alert-icon" aria-hidden="true" width="20" height="20" fill="currentColor">
<path fill-rule="evenodd" d="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16ZM8.28 7.22a.75.75 0 0 0-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 1 0 1.06 1.06L10 11.06l1.72 1.72a.75.75 0 1 0 1.06-1.06L11.06 10l1.72-1.72a.75.75 0 0 0-1.06-1.06L10 8.94 8.28 7.22Z" clip-rule="evenodd"/>
</svg>
<div class="alert-content">
<p class="alert-title">There are 3 errors in this form</p>
<ul class="alert-list">
<li><a href="#email">Email address is required</a></li>
<li><a href="#password">Password must be at least 8 characters</a></li>
<li><a href="#terms">You must agree to the terms of service</a></li>
</ul>
</div>
</div>import { useState, type ReactNode } from "react";
type AlertVariant = "info" | "success" | "warning" | "error";
interface AlertProps {
variant?: AlertVariant;
title?: string;
children: ReactNode;
icon?: ReactNode | false;
dismissible?: boolean;
onDismiss?: () => void;
actions?: ReactNode;
role?: "alert" | "status" | "none";
}
const defaultIcons: Record<AlertVariant, ReactNode> = {
info: <InfoIcon />,
success: <CheckCircleIcon />,
warning: <WarningIcon />,
error: <ErrorIcon />,
};
export default function Alert({
variant = "info",
title,
children,
icon,
dismissible = false,
onDismiss,
actions,
role: ariaRole = "status",
}: AlertProps) {
const [visible, setVisible] = useState(true);
if (!visible) return null;
const handleDismiss = () => {
setVisible(false);
onDismiss?.();
};
const alertIcon = icon === false ? null : icon ?? defaultIcons[variant];
return (
<div
className={`alert alert-${variant}`}
role={ariaRole !== "none" ? ariaRole : undefined}
>
{alertIcon && (
<span className="alert-icon" aria-hidden="true">
{alertIcon}
</span>
)}
<div className="alert-content">
{title && <p className="alert-title">{title}</p>}
<div className="alert-description">{children}</div>
{actions && <div className="alert-actions">{actions}</div>}
</div>
{dismissible && (
<button
type="button"
className="alert-dismiss"
aria-label="Dismiss alert"
onClick={handleDismiss}
>
<CloseIcon aria-hidden="true" />
</button>
)}
</div>
);
}
// Usage
<Alert variant="error" title="Unable to save changes" dismissible>
<p>There was a network error. Please check your connection and try again.</p>
</Alert>
<Alert
variant="warning"
title="Subscription expiring"
actions={
<button className="btn btn-sm btn-primary" onClick={handleRenew}>
Renew now
</button>
}
>
<p>Your subscription expires in 3 days.</p>
</Alert>
<Alert variant="success" role="status">
Your profile has been updated successfully.
</Alert>| Feature | Material 3 | Shadcn/ui | Radix | Ant Design |
|---|---|---|---|---|
| Component | Snackbar (transient) / no direct Alert | Alert (styled div) | No alert primitive | Alert, Notification |
| Variants | No semantic variants | default + destructive only | N/A | success, info, warning, error |
| Dismissible | Snackbar: auto-dismiss | Manual close button | N/A | closable prop |
| Icon | Manual | Manual | N/A | showIcon prop + auto per variant |
| Banner mode | Not built-in | Not built-in | N/A | banner prop (full-width, no icon/border) |
| Actions | Snackbar action button | Manual | N/A | action slot |
| Animation | Material Motion | None (static) | N/A | Ant Motion (slide) |
| Accessibility | Basic | Manual role | N/A | role="alert" by default |
Ant Design Alert is the most complete implementation. It supports all four semantic variants with automatic icons, a banner mode that stretches full-width with no border-radius (for page-level announcements), a closable prop with afterClose callback, and a description prop that separates the title from the body. It also supports a message array for showing multiple messages in one alert.
Shadcn/ui keeps alerts minimal — just default and destructive variants, styled with Tailwind. This is intentional: they treat alerts as styled containers and expect you to compose the content (icons, titles, descriptions, actions) manually. It's flexible but requires more work for each usage.
Material 3 doesn't have a direct "Alert" component — Material philosophy prefers Snackbars (transient) for feedback and Banners (persistent, full-width) for status messages. If you need a classic inline alert in a Material system, you compose it from a Card or custom component.
Radix has no alert primitive because alerts are purely presentational containers with ARIA attributes — there's no complex interaction behavior to abstract. The ARIA part (role="alert", role="status") is trivial to add to a styled <div>.
Bootstrap's Alert deserves a mention for its influence: it established the four-color (info/success/warning/danger) convention that virtually every design system has adopted. The pattern is so universal that users now intuitively understand blue = info, green = success, yellow = warning, red = error without any labels.
For accessible color palettes that work across all four variants in both light and dark mode, use our Color Palette Generator to generate consistent scales.