Skip to content
txbrendan/ui

Alert

beta

A message box for important information, with tones, emphasis levels, and optional icon, title, description, and actions.

Preview

solid

Neutral: a new version is ready
Brand: try the new editor
Danger: the payment failed
Success: the import finished
Warning: your trial ends soon

soft

Neutral: a new version is ready
Brand: try the new editor
Danger: the payment failed
Success: the import finished
Warning: your trial ends soon

outline

Neutral: a new version is ready
Brand: try the new editor
Danger: the payment failed
Success: the import finished
Warning: your trial ends soon

ghost

Neutral: a new version is ready
Brand: try the new editor
Danger: the payment failed
Success: the import finished
Warning: your trial ends soon

parts

Your trial ends in 3 days
Add a payment method to keep your projects and your team's access. Compare plans
No icon
Without an icon, the title and description start at the left edge.
A description can stand alone. A long line wraps under itself and keeps clear of the icon, so the text stays easy to scan on a phone.

Install

  1. 1. Add the registry to components.json, once per app. Without it, the shadcn CLI looks up @txbrendan in a public list that txbrendan/ui does not control.

    npx shadcn@latest registry add "@txbrendan=https://txbrendan.dev/r/{name}.json"
  2. 2. Add the theme, once per app. It replaces your color tokens with ones checked for contrast.

    npx shadcn@latest add @txbrendan/theme
  3. 3. 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">

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>