Skip to content

Alert

A brief, important message that draws attention without interrupting the user's task. Built from scratch with React, TypeScript, and Tailwind CSS.

Code

alert/
alert.tsx
import { cn } from "@/lib/utils";
import { alertVariants } from "./alert-variants";
import type { AlertProps } from "../types";

export function Alert({
  className,
  variant,
  // ponytail: default "alert" matches APG/shadcn; pass role="status" for static banners
  role = "alert",
  ...props
}: AlertProps) {
  return (
    <div
      data-slot="alert"
      role={role}
      className={cn(alertVariants({ variant }), className)}
      {...props}
    />
  );
}

Examples

Basic

Use role="status" for informational banners that are present on first paint. Screen readers treat role="alert" as assertive and may interrupt; static copy rarely needs that.

Preview
Heads up
You can add components to your app using the CLI.

Destructive

Pass variant="destructive" for errors and failures. Keep role="alert" (the default) so dynamically inserted error messages are announced immediately.

Preview

Warning

The warning variant covers cautionary messages that are not hard failures. Pair it with role="status" when the message is advisory rather than urgent.

Preview
Scheduled maintenance
The API will be read-only on Sunday from 2:00 to 4:00 AM UTC.

With action

AlertAction holds buttons or links on the trailing edge. Focus stays in the page; the alert never steals keyboard focus, per the WAI-ARIA alert pattern.

Preview
New version available
Version 2.4 includes performance fixes and updated docs.

Design Decisions

Compound parts instead of a config object

The alert is split into Alert, AlertIcon, AlertContent, AlertTitle, AlertDescription, and AlertAction rather than a single component with an icon, title, description, and action prop bag. Consumers control layout and can omit any slot. A toast-style dismiss button, a second paragraph, or a custom icon component need no API extension.

This follows the shadcn/ui composition model while adding explicit slots for icon, content grouping, and trailing actions. MUI's monolithic Alert with severity and action props is convenient but forces icon and action shapes the library chose upfront.

role="alert" default with an explicit status escape hatch

WAI-ARIA APG assigns role="alert" to live regions that announce brief, important messages without moving focus. React Aria has no Alert component; it exposes announce() via @react-aria/live-announcer for programmatic toasts instead of declarative markup.

Radix, Base UI, and Headless UI also ship no inline alert primitive (only alert dialog, which is modal and focus-trapping). shadcn/ui hard-codes role="alert" on every instance. That is correct for errors injected after user action, but noisy for static page copy that was already visible before hydration.

The default stays role="alert" for parity with APG and shadcn. Demos that represent static informational banners pass role="status" explicitly so readers see both patterns.

Flex layout over CSS grid

shadcn/ui v4 lays out icon and text with grid-cols-[0_1fr] and :has(>svg) selectors. This implementation uses a simple flex row: icon, flex-1 content, optional action. Flex handles the action slot without extra grid areas or col-start rules on every child. The trade-off is slightly more wrapper elements (AlertContent) than shadcn's flat three-part tree.


Trade-offs and limitations

No built-in live announcer for dynamic messages

Mounting <Alert> in JSX is enough when the banner is always visible. When a message appears only after an async failure, screen readers announce it only if the node is inserted while role="alert" is set. React Aria's announce() creates an off-screen live region and avoids layout shift; this component does not wrap that API. Teams that fire many transient toasts may want a dedicated announcer hook on top of these presentational parts.

Icons are consumer-supplied

There is no severity prop that auto-picks an icon and palette. Variants style the container; you pass Lucide (or any SVG) into AlertIcon. That keeps the bundle free of icon imports inside the primitive and matches the portfolio's explicit composition style, but every usage repeats the icon choice MUI and Chakra encode in severity="error".

Pre-rendered alerts may not be spoken on load

APG notes that screen readers generally do not announce alerts already in the DOM when the page finishes loading. Static banners are visual affordances; do not rely on role="alert" alone to inform assistive-tech users of content they would miss without looking at the screen. For critical static warnings, duplicate the information in page heading copy or use visible text near the affected control.