Skip to content

Alert

A persistent, inline message that tells people something important about the page or task in front of them.

SourceRegistry
Scheduled maintenance
The dashboard will be read-only on Sunday from 02:00 to 03:00 UTC.
import { InfoIcon } from "lucide-react"

import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"

export default function AlertDemo() {
  return (
    <Alert variant="info" className="max-w-sm">
      <InfoIcon />
      <AlertTitle>Scheduled maintenance</AlertTitle>
      <AlertDescription>
        The dashboard will be read-only on Sunday from 02:00 to 03:00 UTC.
      </AlertDescription>
    </Alert>
  )
}

Anatomy

Scheduled maintenance
The dashboard is read-only on Sunday from 02:00 to 03:00 UTC.
  1. 1IconTells the kind of message at a glance. It takes the variant's color but never carries the meaning alone.
  2. 2ContainerA bordered, tinted surface. The variant sets its colors and its role: status for most, alert for warnings and errors.
  3. 3TitleOne line that says what happened or what to know.
  4. 4DescriptionThe details and, when there is one, the next step. Neutral text.

Installation

$ pnpm dlx shadcn@latest add https://www.prfct.dev/r/alert.json

Usage

import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
<Alert variant="warning">
  <TriangleAlertIcon />
  <AlertTitle>Your trial ends in 3 days</AlertTitle>
  <AlertDescription>Add a payment method to keep your projects running.</AlertDescription>
</Alert>

Examples

Variants

Five variants: default is neutral, and the other four map to the status scales. A status variant tints its background with step 2, draws its border with step 6, colors its icon with step 11 and its title with step 12; default uses the card surface and the standard border. The description stays neutral in every variant, so the status reads at a glance and the detail reads comfortably, at 4.5:1 or more in both modes.

New CLI release
Version 4.2 adds registry namespaces and faster installs.
Invitations expire after 7 days
Resend an invitation at any time from the members list.
Domain verified
acme.com is ready. Certificates renew automatically.
import {
  CircleAlertIcon,
  CircleCheckIcon,
  InfoIcon,
  TerminalIcon,
  TriangleAlertIcon,
} from "lucide-react"

import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"

export default function AlertVariants() {
  return (
    <div className="flex w-full max-w-lg flex-col gap-3">
      <Alert>
        <TerminalIcon />
        <AlertTitle>New CLI release</AlertTitle>
        <AlertDescription>
          Version 4.2 adds registry namespaces and faster installs.
        </AlertDescription>
      </Alert>
      <Alert variant="info">
        <InfoIcon />
        <AlertTitle>Invitations expire after 7 days</AlertTitle>
        <AlertDescription>
          Resend an invitation at any time from the members list.
        </AlertDescription>
      </Alert>
      <Alert variant="success">
        <CircleCheckIcon />
        <AlertTitle>Domain verified</AlertTitle>
        <AlertDescription>
          acme.com is ready. Certificates renew automatically.
        </AlertDescription>
      </Alert>
      <Alert variant="warning">
        <TriangleAlertIcon />
        <AlertTitle>You&apos;ve used 90% of your build minutes</AlertTitle>
        <AlertDescription>
          Builds will queue once you reach the limit on May 31.
        </AlertDescription>
      </Alert>
      <Alert variant="destructive">
        <CircleAlertIcon />
        <AlertTitle>Payment failed</AlertTitle>
        <AlertDescription>
          We couldn&apos;t charge the card ending in 4242. Update it to keep
          your workspace active.
        </AlertDescription>
      </Alert>
    </div>
  )
}
VariantUse it for
defaultNeutral context that doesn't imply a status: announcements, tips, release notes.
infoHelpful information that affects how people use the page.
successA completed state that stays relevant after the moment has passed.
warningSomething that will become a problem if nobody acts: limits, deprecations, expiring access.
destructiveSomething is broken or blocked right now and needs attention.

With an action

Place one follow-up action in AlertAction. It sits on the right, vertically centered, in a column of its own: the text wraps beside it, however wide the action is. Keep it to a single small button; an alert with a toolbar is a card.

Preview environments are here
Every pull request now gets its own URL.
import { SparklesIcon } from "lucide-react"

import {
  Alert,
  AlertAction,
  AlertDescription,
  AlertTitle,
} from "@/components/ui/alert"
import { Button } from "@/components/ui/button"

export default function AlertWithAction() {
  return (
    <Alert variant="info" className="max-w-lg">
      <SparklesIcon />
      <AlertTitle>Preview environments are here</AlertTitle>
      <AlertDescription>
        Every pull request now gets its own URL.
      </AlertDescription>
      <AlertAction>
        <Button size="xs" variant="outline">
          Enable
        </Button>
      </AlertAction>
    </Alert>
  )
}

Links inside AlertDescription are underlined, set in medium weight and inherit the description's neutral text color, so they stay legible on every tint.

import { TriangleAlertIcon } from "lucide-react"

import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"

export default function AlertWithLink() {
  return (
    <Alert variant="warning" className="max-w-lg">
      <TriangleAlertIcon />
      <AlertTitle>Node.js 20 reaches end of life in April</AlertTitle>
      <AlertDescription>
        Three projects still build on Node.js 20.{" "}
        <a href="#">Review affected projects</a> before builds start failing.
      </AlertDescription>
    </Alert>
  )
}

With a list

When several things need fixing, list them. People scan lists; they skim paragraphs.

import { CircleAlertIcon } from "lucide-react"

import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"

export default function AlertWithList() {
  return (
    <Alert variant="destructive" className="max-w-lg">
      <CircleAlertIcon />
      <AlertTitle>We couldn&apos;t publish your changes</AlertTitle>
      <AlertDescription>
        <p>Fix these issues, then try again:</p>
        <ul className="list-disc pl-5 [&>li]:mt-1">
          <li>The page title is empty.</li>
          <li>Two images are missing alternative text.</li>
          <li>The canonical URL points to a deleted page.</li>
        </ul>
      </AlertDescription>
    </Alert>
  )
}

Title only

A short message doesn't need a description. The icon is optional — drop it for neutral notes that shouldn't draw the eye.

Your changes were saved.
Drafts are only visible to you and your editors.
import { CircleCheckIcon } from "lucide-react"

import { Alert, AlertTitle } from "@/components/ui/alert"

export default function AlertMinimal() {
  return (
    <div className="flex w-full max-w-md flex-col gap-3">
      <Alert variant="success">
        <CircleCheckIcon />
        <AlertTitle>Your changes were saved.</AlertTitle>
      </Alert>
      <Alert>
        <AlertTitle>
          Drafts are only visible to you and your editors.
        </AlertTitle>
      </Alert>
    </div>
  )
}

Guidelines

When to use

  • To explain a condition that affects the whole page or section: an outage, a limit, a pending verification.
  • To summarize a set of form errors above the form, in addition to inline errors on each field.
  • To surface information that must stay visible until the situation changes.

When not to use

  • For confirmation of something the person just did — use a Toast. It appears where attention already is and disappears on its own.
  • For errors on a single field — use FieldError inside a Field, next to the input.
  • For decisions that block progress — use an Alert Dialog.
  • For marketing content. An alert borrows the urgency of status colors; spending it on promotions teaches people to ignore it.

Choose the lowest variant that is true

Status colors are a finite budget. If nothing is wrong, the alert is default or info, even when the message feels important. Reserve warning for things that will break, and destructive for things that are broken.

Dark mode is now available
Switch themes from your profile menu.
DoNeutral news, neutral alert. Color stays meaningful for real problems.
Don’tAnnouncing a feature with a warning trains people to ignore warnings.

Writing

  • Lead with the consequence, not the cause: Builds will queue once you reach the limit, not Build minute usage is at 90%.
  • Say what to do next. Every warning and error should name an action or link to one.
  • Keep titles to one line and descriptions to two sentences. Longer content belongs on its own page.
  • Don't stack alerts. Two or more alerts in one place compete; combine them or show the most severe.

Accessibility

Alerts are live regions, so their content is announced when it appears without moving focus.

  • Politeness follows severity. destructive and warning render role="alert" and are announced immediately, interrupting whatever the screen reader was saying. All other variants render role="status" and wait for a pause. Pass role to override, for example role="note" for static content that should not be announced at all.
  • Insert, don't reveal. Live regions announce changes. An alert that is present on page load is read in document order; one added later — after a failed submission, say — is announced as it appears.
  • Color is never the only signal. Pair every status variant with an icon and a title that states the status in words.
  • Actions stay in the tab order. Buttons and links inside an alert are reachable with Tab and never steal focus when the alert appears.

API reference

Alert

The container. Renders a <div> with data-slot="alert" and a data-variant attribute.

PropTypeDefault
variant

Tints the surface, border, title and icon with the matching status scale.

"default" | "info" | "success" | "warning" | "destructive""default"
role

Defaults to alert for destructive and warning, status otherwise. Override for static notes.

string"alert" | "status"
className

Merged with the variant classes. Use for layout, not color.

stringNo default

AlertTitle

A single line that states the message. Renders a <div>; when the alert has an icon, it starts in the second column.

PropTypeDefault
className

Additional classes.

stringNo default

AlertDescription

Supporting text, links and lists. Uses the neutral muted-foreground color in every variant, so only the icon and the title carry the status color.

PropTypeDefault
className

Additional classes. Paragraphs inside are spaced automatically.

stringNo default

AlertAction

A slot for one follow-up action. It takes a column of its own at the right edge, vertically centered, so the text wraps beside it.

PropTypeDefault
className

Additional classes, e.g. to align the action to the top for tall alerts.

stringNo default