Alert
Static banner that surfaces a piece of context above content. Five tones (default / info / warning / success / muted). Never for transient feedback — use Toast for that.
Anatomy
Heads up
- 1Alert (root)
The div with role='alert'. rounded-lg border bg-card px-4 py-3. Adds pr-9 automatically when onDismiss is set so the X never overlaps content.
- 2Icon slot
First child. A Phosphor icon at weight='light' className='size-4'. Positioned absolutely at left-4 top-3; the variant tints only this icon (destructive also tints title + description).
- 3AlertTitle
h5 with text-sm font-medium and mb-1. Keep it one line. Everything after the icon is shifted right with pl-7 so it never collides.
- 4AlertDescription
div with text-sm text-muted-foreground. Under destructive, it's automatically switched to text-destructive via a data-slot selector.
- 5AlertActions
Optional flex-wrap row of Button variant='outline' size='sm' below the description. Text is reset to foreground so buttons stay neutral inside a destructive alert.
- 6Dismiss (X)
Rendered only when onDismiss is passed. Ghost X button pinned top-right (right-3 top-3), aria-label='Dismiss', wired to your close/hide state.
Variants
Note
Heads up
Careful
Ready
Test mode
Payment failed
<Alert variant="info">
<Info weight="light" className="size-4" />
<AlertTitle>Heads up</AlertTitle>
<AlertDescription>The rule you're editing is currently live.</AlertDescription>
</Alert>With actions
Route updated
Test mode
Payment failed
<Alert>
<Info weight="light" className="size-4" />
<AlertTitle>Route updated</AlertTitle>
<AlertDescription>Your changes are now live on all connected accounts.</AlertDescription>
<AlertActions>
<Button variant="outline" size="sm">Undo</Button>
</AlertActions>
</Alert>
{/* Dismissable: pass onDismiss to render the X */}
<Alert variant="muted" onDismiss={() => {}}>
<Info weight="light" className="size-4" />
<AlertTitle>Test mode</AlertTitle>
<AlertDescription>This account still shows Test mode traffic.</AlertDescription>
</Alert>Inline action
Pass an action to render a right-aligned button (vertically centered) instead of the dismiss X. An alert is either dismissable or actionable, not both.
Rule archived
Sync failed
{/* Button on the right, vertically centered — no dismiss X */}
<Alert action={<Button variant="outline" size="sm">Undo</Button>}>
<CheckCircle weight="light" className="size-4" />
<AlertTitle>Rule archived</AlertTitle>
<AlertDescription>You can restore it from the archive at any time.</AlertDescription>
</Alert>Recipes
Ready-to-copy compositions covering the most common Yuno usages of this atom.
The default persistent notice above a page or form. Info tone + X so users can hide it once acknowledged. Use for 'test mode is on', 'you're viewing a shared view', 'this account is read-only'.
Test mode is on
<Alert variant="info" onDismiss={() => setOpen(false)}>
<Info weight="light" className="size-4" />
<AlertTitle>Test mode is on</AlertTitle>
<AlertDescription>
You're viewing sandbox data. Switch to Live in the top bar to see real traffic.
</AlertDescription>
</Alert>Red icon + red title + red description communicate a real problem. Pair with outline buttons in AlertActions so the user has an immediate next step (Retry, Contact support). Reserved for actual failures, not routine 'delete' flows.
Payment gateway is failing
<Alert variant="destructive">
<WarningCircle weight="light" className="size-4" />
<AlertTitle>Payment gateway is failing</AlertTitle>
<AlertDescription>
3 transactions were rejected in the last hour by Stripe. Retry or contact support.
</AlertDescription>
<AlertActions>
<Button variant="outline" size="sm">Retry all</Button>
<Button variant="outline" size="sm">Contact support</Button>
</AlertActions>
</Alert>Green check for a state that should remain visible after an action completes ('rule published', 'export ready'). If the message is transient - a toast fits better.
Rule published
<Alert variant="success" onDismiss={() => setOpen(false)}>
<CheckCircle weight="light" className="size-4" />
<AlertTitle>Rule published</AlertTitle>
<AlertDescription>
The rule is now active on all connected accounts.
</AlertDescription>
</Alert>Neutral default tone + dismiss + two outline actions (Learn more, Enable). Use to surface a new capability inline above the affected surface - never inside a Dialog.
Smart routing is now available
<Alert onDismiss={() => setOpen(false)}>
<Info weight="light" className="size-4" />
<AlertTitle>Smart routing is now available</AlertTitle>
<AlertDescription>
Route each transaction to the best provider automatically based on cost and success rate.
</AlertDescription>
<AlertActions>
<Button variant="outline" size="sm">Learn more</Button>
<Button variant="outline" size="sm">Enable</Button>
</AlertActions>
</Alert>Import
Copy this import line at the top of the file where you compose this atom.
import {
Alert,
AlertTitle,
AlertDescription,
AlertActions,
} from "@/components/ui/alert";Props
Everything else from the underlying HTML or Radix primitive is forwarded via ...props.
| Prop | Type | Default | Description |
|---|---|---|---|
| Alert.variant | "default" | "info" | "warning" | "success" | "muted" | "destructive" | "default" | Tone. Only tints the icon (destructive also reddens the title + description). All variants render on the same white card + neutral border surface. |
| Alert.onDismiss | () => void | — | When provided, renders an X button in the top-right corner and reserves pr-9 spacing so content never overlaps it. Wire it to your close/hide state. Ignored when `action` is set. |
| Alert.action | ReactNode | — | A right-aligned action (e.g. a Button variant='outline' size='sm'), vertically centered next to the content. Replaces the dismiss X — an alert is either dismissable or actionable, not both. |
| Alert.className | string | — | Merged. The default surface is rounded-lg border bg-card px-4 py-3 — override sparingly. |
| Alert.children | ReactNode | — | Compose in this order: <Icon weight='light' className='size-4' />, <AlertTitle>, <AlertDescription>, then optional <AlertActions>. The icon is positioned absolutely; children after it get pl-7 automatically. |
| AlertTitle.className | string | — | Merged. Default is mb-1 text-sm font-medium. Keep the title one line. |
| AlertDescription.className | string | — | Merged. Default is text-sm text-muted-foreground. Under destructive, an override to text-destructive is applied automatically. |
| AlertActions.className | string | — | Merged. Default is mt-3 flex flex-wrap gap-2 text-foreground. Compose Button variant='outline' size='sm' inside. text-foreground is intentional so buttons stay neutral inside a destructive Alert. |
When to use
- Explaining a persistent state above a form or table.
- Highlighting a limitation or a change the user should be aware of before acting.
When not to use
- Transient confirmations — use Toast.
- Blocking modals — use Dialog.
Usage
- Include an icon that matches the tone (Info / Warning / CheckCircle).
- Keep the title one line and the description under two sentences.
- When the alert needs a button, default to a single right-aligned action (no X). Move buttons below the description only for longer text that must also stay dismissable.
- Don't stack more than one Alert per surface.
- Don't use tone='warning' (destructive) as decoration.
- Don't pair the dismiss X with a right-aligned action — an alert is dismissable or actionable, not both.
Related
Cross-links to atoms and patterns you may reach for next.
- CalloutDocs-only equivalent used inside kit pages (tinted background, richer body). Alert is the product-facing atom.
- ToastFor transient feedback after an action ('Rule created successfully.'). Alert stays; Toast disappears.
- DialogFor blocking decisions the user must resolve. Alert informs in-place; Dialog interrupts.
- Alert dialogFor destructive confirmations. The red text-only Alert never asks 'are you sure' - Alert dialog does.
- BadgeFor inline status inside a row or header instead of a full-width banner.