Skip to content
Component installs need the registry setup— the Base UI shadcn project, the @vegastack namespace and the Cloudflare Access service token.
VegaStack Design

Alert

A status banner — five intents (default and four status colors), an optional icon, and an optional dismiss button.

Status
stable
Since
0.1.0
Accessibility pattern
ARIA status region

Last updated

Heads up
This is an informational alert with a leading icon.

Install

Add Alert from the VegaStack registry. The CLI verifies the item's integrity hash before writing it.

pnpm dlx shadcn@latest add @vegastack/alert

The same command installs the registry items it composes: @vegastack/icon-button.

Usage

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

<Alert intent="info">
  <AlertTitle>Heads up</AlertTitle>
  <AlertDescription>This is an informational alert.</AlertDescription>
</Alert>;

Live announcements

Static alerts announce nothing. Set live when the banner is the RESULT of an action — a failed save, a warning raised by what was just submitted — and a destructive or warning intent becomes an assertive role="alert". Everything else, live or not, stays a polite role="status".

// static — rendered with the page, announces nothing
<Alert intent="info">
  <AlertTitle>Two seats remain on this plan</AlertTitle>
</Alert>

// runtime — announced assertively the moment it mounts
<Alert intent="destructive" live>
  <AlertTitle>Payment declined</AlertTitle>
  <AlertDescription>Update the card on file and try again.</AlertDescription>
</Alert>

Anatomy

Alert is a compound component. Compose the parts inside the root:

Alert — data-slot="alert" | "alert-content" | "alert-dismiss" | "alert-icon"
AlertActions — data-slot="alert-actions"
AlertDescription — data-slot="alert-description"
AlertTitle — data-slot="alert-title"
<Alert intent="success" dismissable onDismiss={handleDismiss}>
  <AlertTitle>Title</AlertTitle>
  <AlertDescription>Supporting description text.</AlertDescription>
  <AlertActions>{/* action buttons */}</AlertActions>
</Alert>
  • Alert — the client root banner (data-slot="alert"). Owns the intent, leading icon, live-region policy, and optional dismiss/self-dismiss behavior.
  • AlertTitle — the bold leading line (data-slot="alert-title").
  • AlertDescription — supporting body text (data-slot="alert-description").
  • AlertActions — a row of action controls below the description (data-slot="alert-actions").

Examples

Variants

default, plus four semantic statuses — info, success, warning, destructive — each with a matching leading icon and status color tokens (bg-X-subtle text-X-text border-X/20).

The strip layout variant is a compact single-line ribbon (icon + message + action, optional dismiss). It is the base pattern for in-content notices and plan/trial rows — there is no separate "inline banner" or "plan banner" component. For the full-width inverse strip across the top of a page, use AnnouncementBanner instead.

Default
A neutral message with no status connotation.
Info
Useful context the user should be aware of.
Success
Your changes have been saved.
Warning
Your subscription expires in 3 days.
Error
Your last payment could not be processed.

Dismissable

Set dismissable to render a close button. Provide onDismiss to control visibility yourself, or omit it to let the alert remove itself from the DOM.

Subscription expiring
Renew within 3 days to avoid interruption.
New feature
Check out the new dashboard analytics.

Actions & controlled dismiss

Add an AlertActions row for follow-up controls, and pass onDismiss to drive visibility from your own state instead of letting the alert self-remove. This is the recommended production path — it keeps the alert in React's control so you can re-show it, log the dismissal, or coordinate other UI.

Subscription expiring
Renew within 3 days to avoid interruption.

Icon options

Pass a custom leading icon (any lucide-react element) to override the intent's default, or set hideIcon to drop the leading icon gutter entirely.

Custom icon
Pass any lucide icon via the `icon` prop.
No icon
`hideIcon` removes the leading icon gutter.

Variant matrix

Each intent rendered in its plain (icon-only) form and again with an AlertActions row, so the icon gutter and action layout read consistently across every tone.

default
With its default leading icon.
info
With its default leading icon.
success
With its default leading icon.
warning
With its default leading icon.
destructive
With its default leading icon.
default
With an action row below.
info
With an action row below.
success
With an action row below.
warning
With an action row below.
destructive
With an action row below.

Strip variant

variant="strip" is the compact single-line info ribbon — centered icon + copy, tighter padding — for settings banners and inline notices (distinct from the block alert).

Changes to your profile apply to all of your workspaces.
Your trial ends in 3 days.

Playground

Try every intent with the icon and dismiss options, then copy the generated JSX.

Heads up
Your trial ends in 7 days.
<Alert>
  <AlertTitle>Heads up</AlertTitle>
  <AlertDescription>Your trial ends in 7 days.</AlertDescription>
</Alert>

API Reference

Alert

PropTypeDefaultDescription
dismissablebooleanfalseRender a dismiss (close) button in the top-right corner.
dismissLabelstring"Dismiss"Accessible label for the dismiss button.
hideIconbooleanfalseHide the leading icon entirely (overrides icon).
iconReact.ReactNodeCustom leading icon. Falls back to the intent's default icon. Pass a lucide-react icon element (e.g. <Bell />).
intentAlertIntent"default"Status intent — drives the color tokens and the default leading icon.
livebooleanfalseMark this alert as a runtime announcement — it appeared (or its copy changed) AFTER the page had settled, in response to something the user did. Only then does an assertive role="alert" become correct, and only for destructive/warning; every other intent stays polite. Leave false for a statically rendered banner: a status region that is already in the DOM at load announces nothing, so a page of three static alerts stays silent instead of interrupting three times (D23, WAI-ARIA alert is for time-sensitive, important messages).
onDismiss(() => void)Called when the dismiss button is clicked. When dismissable is set and no handler is provided, the alert removes itself from the DOM internally.
variant"default" | "strip""default"Layout — default block alert, or strip: the compact single-line info ribbon (settings banners, inline notices).

Data attributes and CSS variables on Alert

AttributeValues
data-intentmirrors a prop or state value
data-live""
data-slot"alert" | "alert-content" | "alert-dismiss" | "alert-icon"
data-variantmirrors a prop or state value

AlertTitle

AlertTitle adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).

Data attributes and CSS variables on AlertTitle

AttributeValues
data-slot"alert-title"

AlertDescription

AlertDescription adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).

Data attributes and CSS variables on AlertDescription

AttributeValues
data-slot"alert-description"

AlertActions

AlertActions adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).

Data attributes and CSS variables on AlertActions

AttributeValues
data-slot"alert-actions"

Accessibility

  • The root is a polite role="status" region by default, for every intent. A live region that is already in the DOM when the page loads announces nothing, so a page carrying three static alerts stays silent instead of interrupting three times.
  • Pass live for a banner that appears (or re-words) in response to something the user did. With live, a destructive or warning intent escalates to the assertive role="alert" — the only case WAI-ARIA reserves an interruption for; the other intents stay polite.
  • The leading icon is decorative (aria-hidden); meaning is carried by the title and description text.
  • The dismiss button is a native <button type="button"> with an accessible label (dismissLabel, default "Dismiss").
  • The dismiss button shows a :focus-visible ring (outline-ring) — never outline: none.
KeyAction
TabMove focus to the dismiss button (when dismissable).
Enter / SpaceActivate the focused dismiss button.
ContractStates tested
Behaviourdefault, error, open, saved, success
Accessibilitylabeled, alert-announcement, semantic-html
Visualdefault, hover, error, success

Do / Don't

Do
Use the intent that matches the message — destructive for errors, success for confirmations.
Don't
Use an Alert for transient feedback after an action — use a toast instead.

On this page