Alert
betaA message box for important information, with tones, emphasis levels, and optional icon, title, description, and actions.
Preview
solid
soft
outline
ghost
parts
Install
1. Add the registry to
components.json, once per app. Without it, the shadcn CLI looks up@txbrendanin a public list that txbrendan/ui does not control.npx shadcn@latest registry add "@txbrendan=https://txbrendan.dev/r/{name}.json"2. Add the theme, once per app. It replaces your color tokens with ones checked for contrast.
npx shadcn@latest add @txbrendan/theme3. Add the component.
npx shadcn@latest add @txbrendan/alert
Use it for
- Telling people something important about the page or their task: a failed payment, planned downtime, a finished import.
- Use tone to say what kind of message it is: danger for errors, warning for risks, success for done, brand or neutral for news.
- Soft, the default, or outline fits most messages. Solid is the loudest, so save it for the one message that must not be missed.
- Add role='alert' only for an urgent message that appears after the page loads, like a failed save.
- Add role='status' to an alert that stays on the page while its text changes, like 'Saving…' then 'Saved'.
Avoid it for
- role='alert' on a message that is there when the page loads. Screen readers would interrupt people for news that is not new.
- Buttons or links inside a solid alert. Button colors and focus rings are not checked on solid fills. Use soft or outline when the alert has actions.
- A problem with one field, row, or card. Say it under the thing with Notice.
- A choice people must make before they go on. Use a dialog.
- Short confirmations that should go away on their own. Use Toast.
Props
- tone
Color role.
"neutral" | "brand" | "danger" | "success" | "warning" · default "neutral"
- emphasis
How loud the alert is. Soft by default, unlike Badge and Button, because most alerts carry plain information.
"solid" | "soft" | "outline" | "ghost" · default "soft"
- role
Unset by default. Set it only for messages that appear or change after load. TypeScript rejects other roles.
"alert" | "status"
- className
Extra classes. Later classes win, so className='rounded-none' replaces the radius.
string
- AlertIcon
Part. Holds one icon beside the first line of text. aria-hidden by default.
ComponentProps<"div">
- AlertTitle
Part. A short summary in medium weight. A div, so it never breaks your heading order.
ComponentProps<"div">
- AlertDescription
Part. The details. Links inside it are underlined.
ComponentProps<"div">
- AlertActions
Part. A row of buttons or links under the text. It wraps on small screens.
ComponentProps<"div">
| Prop | Type | Default | What it does |
|---|---|---|---|
| tone | "neutral" | "brand" | "danger" | "success" | "warning" | "neutral" | Color role. |
| emphasis | "solid" | "soft" | "outline" | "ghost" | "soft" | How loud the alert is. Soft by default, unlike Badge and Button, because most alerts carry plain information. |
| role | "alert" | "status" | - | Unset by default. Set it only for messages that appear or change after load. TypeScript rejects other roles. |
| className | string | - | Extra classes. Later classes win, so className='rounded-none' replaces the radius. |
| AlertIcon | ComponentProps<"div"> | - | Part. Holds one icon beside the first line of text. aria-hidden by default. |
| AlertTitle | ComponentProps<"div"> | - | Part. A short summary in medium weight. A div, so it never breaks your heading order. |
| AlertDescription | ComponentProps<"div"> | - | Part. The details. Links inside it are underlined. |
| AlertActions | ComponentProps<"div"> | - | Part. A row of buttons or links under the text. It wraps on small screens. |
Accessibility
- Renders a <div> with no role, so an alert that is there at load is read in order, like the rest of the page.
- role="alert" makes screen readers read the message at once, even mid-sentence. Use it only for urgent messages added after load.
- role="status" waits until the screen reader is quiet. Keep that alert on the page and change its text. Some screen readers miss a status region that arrives together with its text.
- AlertIcon is aria-hidden, and color is not read out. The title must say what kind of message it is, like "Payment failed".
- AlertTitle is a <div>, not a heading. Put an <h2> or <h3> inside it if the alert needs to be in the page outline.
- The theme tests hold alert text to 4.5:1: solid and soft text on their own fills, and outline and ghost text on the page background.
Examples
Information that is on the page at load
import { Info } from "lucide-react";
<Alert tone="brand" emphasis="soft">
<AlertIcon>
<Info />
</AlertIcon>
<AlertTitle>Planned maintenance</AlertTitle>
<AlertDescription>The dashboard is read-only on Sunday from 02:00 to 04:00 UTC.</AlertDescription>
</Alert>An error after a failed save
import { CircleAlert } from "lucide-react";
function SaveError({ error }: { error: string | null }) {
if (!error) return null;
return (
<Alert role="alert" tone="danger" emphasis="soft">
<AlertIcon>
<CircleAlert />
</AlertIcon>
<AlertTitle>Your changes were not saved</AlertTitle>
<AlertDescription>{error}</AlertDescription>
</Alert>
);
}A status that changes while it stays on the page
function SaveStatus({ saving }: { saving: boolean }) {
return (
<Alert role="status" emphasis="outline">
<AlertDescription>{saving ? "Saving…" : "All changes saved"}</AlertDescription>
</Alert>
);
}With actions (needs @txbrendan/button)
import { Button } from "@/components/ui/button";
<Alert tone="warning" emphasis="soft">
<AlertTitle>Your trial ends in 3 days</AlertTitle>
<AlertDescription>
Add a payment method to keep your projects. <a href="/pricing">Compare plans</a>
</AlertDescription>
<AlertActions>
<Button size="sm" tone="warning">
Add payment method
</Button>
<Button size="sm" tone="warning" emphasis="soft">
Remind me later
</Button>
</AlertActions>
</Alert>