# Alert

Present an inline message with a title and optional actions.

Maintenance notice with icon

[Complete TSX file](/examples/alert/default.tsx)

```tsx
"use client";

import { InfoIcon } from "lucide-react";
import {
  Alert,
  AlertDescription,
  AlertTitle,
} from "@/siteplane/components/alert";

export default function Example() {
  return (
    <Alert className="max-w-md" role="status">
      <InfoIcon aria-hidden="true" />
      <AlertTitle>Scheduled maintenance</AlertTitle>
      <AlertDescription>
        Projects are read-only on Sunday from 02:00 to 03:00 UTC.
      </AlertDescription>
    </Alert>
  );
}
```

## Installation

Complete [one-time setup](/docs/installation/) first.

```bash
pnpm dlx shadcn@4.18.0 add @siteplane/alert
```

With npm: `npx shadcn@4.18.0 add @siteplane/alert`. [Registry JSON](/registry/alert.json) lists source files and dependencies.

For this page’s examples, also install:

```bash
pnpm dlx shadcn@4.18.0 add @siteplane/button @siteplane/card
```

## Usage

```tsx
import { Alert, AlertTitle } from "@/siteplane/components/alert";

<Alert>
  <AlertTitle>Changes saved</AlertTitle>
</Alert>;
```

## Composition

```text
Alert
├── icon (optional)
├── AlertTitle
├── AlertDescription
├── AlertAction
└── AlertClose (optional)
```

Place the icon directly under Alert, before the title; the alert then reserves a column for it.

## Variants

Choose a semantic variant, pair it with a matching icon and state the status in the text. The variant also sets the role. A default, info or success alert is a polite `status`, and an error or warning alert is an `alert` that a screen reader announces at once. Pass `role` to change it.

Alert variants

[Complete TSX file](/examples/alert/variants.tsx)

```tsx
"use client";

import {
  CircleAlertIcon,
  CircleCheckIcon,
  InfoIcon,
  TriangleAlertIcon,
} from "lucide-react";
import {
  Alert,
  AlertDescription,
  AlertTitle,
} from "@/siteplane/components/alert";

const alerts = [
  {
    variant: "default",
    role: "status",
    icon: InfoIcon,
    title: "Comments are turned off",
    description: "Members can view this project but cannot add comments.",
  },
  {
    variant: "info",
    role: "status",
    icon: InfoIcon,
    title: "New version available",
    description: "Reload the page to get the latest features.",
  },
  {
    variant: "success",
    role: "status",
    icon: CircleCheckIcon,
    title: "Payment received",
    description: "Invoice INV-1042 has been paid. A receipt is on its way.",
  },
  {
    variant: "warning",
    role: "alert",
    icon: TriangleAlertIcon,
    title: "Storage almost full",
    description: "Your workspace has used 90% of its storage.",
  },
  {
    variant: "error",
    role: "alert",
    icon: CircleAlertIcon,
    title: "Payment failed",
    description: "Update your card to keep your subscription active.",
  },
] as const;

export default function Example() {
  return (
    <div className="grid w-full max-w-md gap-3">
      {alerts.map(({ variant, role, icon: Icon, title, description }) => (
        <Alert key={variant} role={role} variant={variant}>
          <Icon aria-hidden="true" />
          <AlertTitle>{title}</AlertTitle>
          <AlertDescription>{description}</AlertDescription>
        </Alert>
      ))}
    </div>
  );
}
```

## With actions

Put buttons in AlertAction. They sit beside the message on larger screens and below it on small screens; connect their callbacks in your application.

Alert with actions

[Complete TSX file](/examples/alert/action.tsx)

```tsx
"use client";

import { InfoIcon } from "lucide-react";
import {
  Alert,
  AlertAction,
  AlertDescription,
  AlertTitle,
} from "@/siteplane/components/alert";
import { Button } from "@/siteplane/components/button";

export default function Example() {
  return (
    <Alert className="max-w-md" role="status" variant="info">
      <InfoIcon aria-hidden="true" />
      <AlertTitle>Invite your team</AlertTitle>
      <AlertDescription>
        Projects move faster when everyone can comment and review.
      </AlertDescription>
      <AlertAction>
        <Button size="sm" variant="ghost">
          Dismiss
        </Button>
        <Button size="sm">Invite members</Button>
      </AlertAction>
    </Alert>
  );
}
```

## Page banner

Use `layout="banner"` for something that concerns the whole page, such as customers who can't book, at the top of the page above its header. The banner takes the tint of its tone across the full width, with a hairline below it, a short title and one short sentence. Only the icon carries the tone; the title stays in the primary text color.

The action of a banner is always a text link in the primary text color, underlined. The standard places it at the end of the row, in AlertAction (`Button variant="link" profile="inline"`). The icon, the text, the action and the close control stand on one row while the banner's own width allows it. Below 32rem of its own width, the icon and the close control sit on the title's line, the text runs between them and the action goes under the text.

Page banners with the action at the end

[Complete TSX file](/examples/alert/banner.tsx)

```tsx
"use client";

import { CircleAlertIcon, TriangleAlertIcon } from "lucide-react";
import {
  Alert,
  AlertAction,
  AlertClose,
  AlertDescription,
  AlertTitle,
} from "@/siteplane/components/alert";
import { Button } from "@/siteplane/components/button";

export default function Example() {
  return (
    <div className="w-full">
      <Alert layout="banner" variant="error">
        <CircleAlertIcon aria-hidden="true" />
        <AlertTitle>Customers can't book since Oct 12</AlertTitle>
        <AlertDescription>
          Stripe needs details from the business to take payments.
        </AlertDescription>
        <AlertAction>
          <Button
            profile="inline"
            render={<a href="#booking" />}
            variant="link"
          >
            Open booking
          </Button>
        </AlertAction>
        <AlertClose />
      </Alert>
      <Alert layout="banner" variant="warning">
        <TriangleAlertIcon aria-hidden="true" />
        <AlertTitle>Changes show up to a minute late</AlertTitle>
        <AlertDescription>
          Check the website's address in Settings.
        </AlertDescription>
        <AlertAction>
          <Button
            profile="inline"
            render={<a href="#settings" />}
            variant="link"
          >
            Open Settings
          </Button>
        </AlertAction>
        <AlertClose />
      </Alert>
    </div>
  );
}
```

The same link can also end the sentence, so the banner stays two lines high. The link keeps its words together. A text action never reads like a red delete button, also on an error banner.

Page banners with the link in the text

[Complete TSX file](/examples/alert/banner-link.tsx)

```tsx
"use client";

import { CircleAlertIcon, TriangleAlertIcon } from "lucide-react";
import {
  Alert,
  AlertClose,
  AlertDescription,
  AlertTitle,
} from "@/siteplane/components/alert";
import { Button } from "@/siteplane/components/button";

export default function Example() {
  return (
    <div className="w-full">
      <Alert layout="banner" variant="error">
        <CircleAlertIcon aria-hidden="true" />
        <AlertTitle>Customers can't book since Oct 12</AlertTitle>
        <AlertDescription>
          <p>
            Stripe needs details from the business to take payments.{" "}
            <Button
              profile="inline"
              render={<a href="#booking" />}
              variant="link"
            >
              Open booking
            </Button>
          </p>
        </AlertDescription>
        <AlertClose />
      </Alert>
      <Alert layout="banner" variant="warning">
        <TriangleAlertIcon aria-hidden="true" />
        <AlertTitle>Changes show up to a minute late</AlertTitle>
        <AlertDescription>
          <p>
            Check the website's address in Settings.{" "}
            <Button
              profile="inline"
              render={<a href="#settings" />}
              variant="link"
            >
              Open Settings
            </Button>
          </p>
        </AlertDescription>
        <AlertClose />
      </Alert>
    </div>
  );
}
```

## Card band

Use `layout="band"` for a problem that belongs to one card. Place the Alert directly under the CardHeader: it runs across the card's full width, starts its icon where the card's text starts and lays out by its own width, not the window's. It takes the action at the end or the link in the text, like a banner.

Band in a card

[Complete TSX file](/examples/alert/band.tsx)

```tsx
"use client";

import { TriangleAlertIcon } from "lucide-react";
import {
  Alert,
  AlertAction,
  AlertClose,
  AlertDescription,
  AlertTitle,
} from "@/siteplane/components/alert";
import { Button } from "@/siteplane/components/button";
import {
  Card,
  CardDescription,
  CardHeader,
  CardPanel,
  CardTitle,
} from "@/siteplane/components/card";

export default function Example() {
  return (
    <Card className="w-full max-w-xl">
      <CardHeader>
        <CardTitle>Bookings</CardTitle>
        <CardDescription>
          Requests from the website, newest first.
        </CardDescription>
      </CardHeader>
      <Alert layout="band" variant="warning">
        <TriangleAlertIcon aria-hidden="true" />
        <AlertTitle>Two requests wait for a reply</AlertTitle>
        <AlertDescription>Guests hear back within a day.</AlertDescription>
        <AlertAction>
          <Button
            profile="inline"
            render={<a href="#requests" />}
            variant="link"
          >
            Answer now
          </Button>
        </AlertAction>
        <AlertClose />
      </Alert>
      <CardPanel className="text-sm">12 requests this week</CardPanel>
    </Card>
  );
}
```

## Closing

`AlertClose` adds the kit's ghost close control, labelled "Close". It closes the Alert, which glides up and fades out with the kit's motion while the content below moves up; with reduced motion it closes at once. When focus was inside the Alert, it moves to the next element after it, never to the page. The Alert closes by itself, or set `open` and `onOpenChange` to decide in your application how long it stays closed. An inline Alert with `AlertClose` needs `defaultOpen` or `open` to collapse with motion.

## API reference

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| Alert.variant | default \| info \| success \| warning \| error | default | Color treatment. |
| Alert.layout | inline \| banner \| band | inline | A surface in the content flow, a band across the top of a page, or a band at the top of a Card. |
| Alert.open | boolean | unset | Shows the Alert, controlled. Closing collapses it with the kit's motion. |
| Alert.defaultOpen | boolean | true | Shows the Alert at first, uncontrolled. |
| Alert.onOpenChange | (open: boolean) => void | unset | Called with false when AlertClose closes the Alert. |
| AlertClose.aria-label | string | Close | The accessible name of the close control. |
| Alert.role | ARIA role | alert for error and warning, status otherwise | Default, info and success are a polite status. Pass a role to override it. |
The four text and action parts accept native div attributes, refs, children and
string className, and `AlertClose` accepts native button attributes. `Alert`
owns the surface, the grid and the open state; `AlertTitle` is the emphasized
text; `AlertDescription` lays out supporting content; `AlertAction` places
actions beside the message on larger screens and below on smaller screens;
`AlertClose` closes the Alert. Titles are divs, not semantic headings. There is
no timer.

[Read the installed source](/source/alert).

## Usage notes

Reserve assertive alert announcements for urgent changes. Keep a clear recovery action for errors, and do not announce all static informational messages as alerts.
