Skip to content

Alert

Displays an important message to attract the user's attention without interrupting workflow.

  • Banner
  • Notification Banner
  • Callout

Overview

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:

  • Communicating the result of an action ("Your changes have been saved successfully")
  • Warning about potential issues ("Your subscription expires in 3 days")
  • Displaying errors that affect the entire page or form ("Unable to load your data. Please try again.")
  • Providing informational context ("This feature is in beta. Some functionality may change.")
  • System-wide announcements ("Scheduled maintenance on March 15, 2026")

When NOT to use an Alert:

  • For transient success feedback — use a Toast that auto-dismisses
  • For errors on specific form fields — use inline validation on the Text Input itself
  • For critical actions requiring user choice — use a Dialog or Alert Dialog
  • For permanent, ever-present information — use a callout or aside (not styled as an alert)
  • For notification counts or badges — use a Badge

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.

Variants

Semantic Variants

VariantColorIconPurpose
InfoBlueℹ️ (information circle)Neutral information, tips, context. No urgency.
SuccessGreen✓ (checkmark circle)Confirmation that an action completed successfully.
WarningYellow/Amber⚠️ (triangle exclamation)Something needs attention but isn't blocking.
ErrorRed✕ (X circle) or ❗Something went wrong. Action may be required.

Visual Variants

VariantDescription
FilledSolid background color (light tint of the semantic color). High visibility.
OutlinedWhite/transparent background with a colored left border (4px). Subtle but clear.
SoftVery light tinted background with matching text color. Minimal visual weight.
BannerFull-width, typically at the top of the page or content area. No border-radius.
InlineSits within the content flow. Has border-radius. Standard width.

Structural Variants

VariantDescription
SimpleIcon + single line of text
With titleIcon + bold title + description text
With actionsIcon + text + action buttons or links ("Retry", "Dismiss", "Learn more")
With listIcon + title + bulleted list of items (e.g., multiple form errors)
DismissibleIncludes a close (✕) button to remove the alert

Size Variants

SizePaddingFont SizeUse Case
Small8px 12px13pxInline field-level messages, compact UIs
Medium12px 16px14pxDefault page-level alerts
Large16px 20px16pxFull-width banners, critical system alerts

Properties

Alert Properties

PropertyTypeDefaultDescription
variant'info' | 'success' | 'warning' | 'error''info'Semantic variant controlling color and icon
titlestring—Bold heading text
childrenReactNode—Alert body content
iconReactNode | falseAuto (based on variant)Custom icon. Set false to hide.
dismissiblebooleanfalseShows a close button
onDismiss() => void—Callback when dismissed
actionsReactNode—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 Mappings

Design Token Mappings

Token CategoryToken ExampleAlert Usage
Color – Info Background--color-info-50Info variant background
Color – Info Border--color-info-200Info variant left border
Color – Info Icon--color-info-600Info icon color
Color – Info Text--color-info-800Info title color
Color – Success--color-success-50 / -200 / -600 / -800Success variant tokens
Color – Warning--color-warning-50 / -200 / -600 / -800Warning variant tokens
Color – Error--color-error-50 / -200 / -600 / -800Error variant tokens
Border Radius--radius-md (8px) or --radius-lg (12px)Alert container corners. Preview with Border Radius Generator.
Border – Left Accent4px solid --color-[variant]-500Outlined 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-semiboldAlert title
Typography – Body--font-size-sm, --font-weight-normalAlert description

Use the Color Palette Generator to generate consistent semantic color scales for all four variants.

States

Alert States

StateBehavior
VisibleAlert is displayed inline in the content flow. Content before and after adjusts.
EnteringFade in + slide down (optional). 200ms ease-out.
DismissingFade out + slide up. On completion, the alert is removed from the DOM (not just hidden). Content below shifts up.
DismissedAlert is removed. If server-driven, the dismissal state may be persisted.

Contextual States

ContextBehavior
Page-levelAlert appears at the top of the content area, below the header. Full width of the content column.
Section-levelAlert appears within a specific section (form, card, panel). Scoped to that section's width.
BannerFull viewport width, fixed or sticky at the top of the page. Used for system announcements.
Form error summarySpecial alert at the top of a form listing all validation errors. Each error links to its field.

Dynamic Alerts

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.
  • Neither: For alerts that are present on page load (not dynamically inserted), no ARIA role is needed — the user will encounter them naturally while reading.

Accessibility

WCAG Requirements

CriterionLevelRequirement
SC 1.4.1 Use of ColorADon'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)AAAlert 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 ContrastAAIcons and borders: 3:1 against adjacent background.
SC 4.1.3 Status MessagesAADynamic alerts must be announced to screen readers without receiving focus. Use role="alert" or role="status".
SC 2.2.1 Timing AdjustableAIf 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.

ARIA Implementation

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>

Dismissible Alert Accessibility

  • The dismiss button must have aria-label="Dismiss" or aria-label="Close alert"
  • After dismissal, focus should move to a logical location (the next element in the flow, or the preceding heading)
  • The dismissal should be announced: inject a visually-hidden "Alert dismissed" text in an aria-live region

Color Contrast Per Variant

This is the biggest accessibility pitfall with alerts. Typical failures:

VariantCommon FailureFix
SuccessDark green text on light green bg fails 4.5:1Use --color-success-800 on --color-success-50 — verify exact values
WarningOrange text on yellow bg almost always failsUse dark amber or near-black text on light yellow
InfoLight blue text on light blue bgUse --color-info-800 for text, not --color-info-500
ErrorUsually passes — red on light pink has inherently higher contrastStill 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.

Usage Guidelines

Do's

  • ✅ Use the correct semantic variant. Don't use a warning alert for an error, or an info alert for a success message. The color and icon should match the meaning.
  • ✅ Lead with the most important information. "Your account has been suspended" first, explanation second.
  • ✅ Include an action when possible. "Your session expires in 5 minutes. [Extend session]" is more useful than just the warning.
  • ✅ Use alert as a form error summary. At the top of the form, show "There are 3 errors below" with links to each field. This is especially valuable for long forms.
  • ✅ Keep alert text concise. One sentence for the title, 1–2 sentences for the description. If you need more, link to a detail page.
  • ✅ Make page-level error alerts persistent until the error is resolved. Don't auto-dismiss errors.

Don'ts

  • ❌ Don't stack more than 2–3 alerts at once. If you have that many, consolidate or redesign the page state.
  • ❌ Don't use alerts for marketing. "New feature! Check it out!" is a banner, not an alert. Alerts are for status and feedback.
  • ❌ Don't auto-dismiss error alerts. The user needs time to read, understand, and act. Success alerts can auto-dismiss; errors should not.
  • ❌ Don't place alerts at the bottom of the page where users might not see them. Position them near the relevant content (top of the form, inside the affected section).
  • ❌ Don't use an alert where a Toast would suffice. If it's brief feedback that doesn't require action ("Copied to clipboard"), a Toast is less intrusive.
  • ❌ Don't use colored text on colored backgrounds without checking contrast. This is the #1 accessibility failure in alert components. Validate every color combination with the Contrast Checker.

Content Guidelines

  • Title: Short, descriptive, not alarming ("Payment method expiring" not "URGENT: PAYMENT ISSUE!!!")
  • Description: Explain the situation and what the user can do about it
  • Action labels: Verb-first, specific ("Update payment method", "View details", "Try again")
  • Error lists: Link each error to the corresponding field: "Email address is required" → clicking scrolls to and focuses the email field

Code Snippets

html
<!-- 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>
tsx
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>

Design Systems

Cross-System Comparison

FeatureMaterial 3Shadcn/uiRadixAnt Design
ComponentSnackbar (transient) / no direct AlertAlert (styled div)No alert primitiveAlert, Notification
VariantsNo semantic variantsdefault + destructive onlyN/Asuccess, info, warning, error
DismissibleSnackbar: auto-dismissManual close buttonN/Aclosable prop
IconManualManualN/AshowIcon prop + auto per variant
Banner modeNot built-inNot built-inN/Abanner prop (full-width, no icon/border)
ActionsSnackbar action buttonManualN/Aaction slot
AnimationMaterial MotionNone (static)N/AAnt Motion (slide)
AccessibilityBasicManual roleN/Arole="alert" by default

Notable Approaches

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.

FeedbackBannerNotification BannerCallout