# Alert (/ui/components/react/alert)



<Playground component="alert" />

## Usage [#usage]

```tsx
import { Alert, AlertIcon, AlertTitle, AlertDescription, AlertAction } from '@appica/ui-react/alert'
```

```tsx
<Alert variant="info">
  <AlertIcon>
    <InfoCircleFilled />
  </AlertIcon>
  <AlertTitle>Scheduled maintenance</AlertTitle>
  <AlertDescription>Some features may be unavailable Sunday night.</AlertDescription>
</Alert>
```

`Alert` is a banner for a message that lives **in the page layout** — a status, a heads-up, a result. Compose it from its parts, all under `@appica/ui-react/alert`:

* **`Alert`** — the `role="alert"` container. Sets the `variant` color and `layout`, and owns the optional dismiss behavior.
* **`AlertIcon`** — a leading icon slot that automatically takes the variant's color.
* **`AlertTitle`** — the headline (`<h5>`).
* **`AlertDescription`** — the supporting body text.
* **`AlertAction`** — a trailing row for buttons.

Every part is optional except a meaningful label — most alerts have at least an `AlertTitle`. The slots are placed by a grid, so you can include only the ones you need and they'll lay out correctly in either layout.

For a transient, stacked notification that appears and disappears on its own, reach for a [`Toast`](/ui/components/react/toast) instead; for a blocking confirmation, use an [`Alert Dialog`](/ui/components/react/alert-dialog). `Alert` is for messages that sit inline with your content.

## Examples [#examples]

### Default [#default]

The neutral `default` variant with an icon, title, and description. Drop the parts you need inside `Alert` and the grid arranges them.

```tsx
import { Alert, AlertIcon, AlertTitle, AlertDescription } from '@appica/ui-react/alert'
import { InfoCircle } from '@appica/icons-react'

export default function AlertDefault() {
  return (
    <div className="w-full max-w-md">
      <Alert>
        <AlertIcon>
          <InfoCircle />
        </AlertIcon>
        <AlertTitle>Heads up</AlertTitle>
        <AlertDescription>
          A new version of the dashboard is available — refresh to pick up the latest features.
        </AlertDescription>
      </Alert>
    </div>
  )
}
```

### Variants [#variants]

Seven variants color the alert for its purpose: `default`, `primary`, `secondary`, `info`, `success`, `warning`, and `error`. The `AlertIcon` inherits the variant's accent color automatically.

```tsx
import { Alert, AlertIcon, AlertTitle, AlertDescription } from '@appica/ui-react/alert'
import {
  Bell,
  Sparkle,
  InfoCircleFilled,
  CircleCheckFilled,
  AlertTriangleFilled,
  CircleXFilled,
} from '@appica/icons-react'

const VARIANTS = [
  { variant: 'default', icon: Bell, title: 'Update available', desc: 'Version 2.4 is ready to install.' },
  { variant: 'primary', icon: Sparkle, title: 'New feature', desc: 'You can now schedule reports to run weekly.' },
  { variant: 'secondary', icon: InfoCircleFilled, title: 'Did you know?', desc: 'Press ⌘K to search from anywhere.' },
  {
    variant: 'info',
    icon: InfoCircleFilled,
    title: 'Maintenance window',
    desc: 'We will be offline Sunday 02:00–03:00 UTC.',
  },
  { variant: 'success', icon: CircleCheckFilled, title: 'Payment received', desc: 'Your invoice has been settled.' },
  {
    variant: 'warning',
    icon: AlertTriangleFilled,
    title: 'Storage almost full',
    desc: 'You have used 92% of your quota.',
  },
  {
    variant: 'error',
    icon: CircleXFilled,
    title: 'Payment failed',
    desc: 'We could not charge your card on file.',
  },
] as const

export default function AlertVariants() {
  return (
    <div className="flex w-full max-w-md flex-col gap-3">
      {VARIANTS.map(({ variant, icon: Icon, title, desc }) => (
        <Alert key={variant} variant={variant}>
          <AlertIcon>
            <Icon />
          </AlertIcon>
          <AlertTitle>{title}</AlertTitle>
          <AlertDescription>{desc}</AlertDescription>
        </Alert>
      ))}
    </div>
  )
}
```

### Inline layout [#inline-layout]

Set `layout="inline"` to flow the icon, title, and description onto a single row once there's room (the alert is container-query aware, so it falls back to the stacked block layout when it gets narrow). Good for slim page-top banners.

```tsx
import { Alert, AlertIcon, AlertTitle, AlertDescription } from '@appica/ui-react/alert'
import { InfoCircleFilled } from '@appica/icons-react'

export default function AlertInline() {
  return (
    <div className="w-full max-w-xl">
      <Alert layout="inline" variant="info">
        <AlertIcon>
          <InfoCircleFilled />
        </AlertIcon>
        <AlertTitle>Scheduled maintenance</AlertTitle>
        <AlertDescription>Some features may be unavailable Sunday night.</AlertDescription>
      </Alert>
    </div>
  )
}
```

### With actions [#with-actions]

Add an `AlertAction` row for buttons — say a primary action and a dismiss. It sits below the text in the block layout and trails the message inline.

```tsx
import { Alert, AlertIcon, AlertTitle, AlertDescription, AlertAction } from '@appica/ui-react/alert'
import { Button } from '@appica/ui-react/button'
import { AlertTriangleFilled } from '@appica/icons-react'

export default function AlertActions() {
  return (
    <div className="w-full max-w-md">
      <Alert variant="warning">
        <AlertIcon>
          <AlertTriangleFilled />
        </AlertIcon>
        <AlertTitle>Your trial ends in 3 days</AlertTitle>
        <AlertDescription>Upgrade now to keep access to your projects and team members.</AlertDescription>
        <AlertAction>
          <Button variant="ghost" size="sm" className="hover:before:bg-background">
            Maybe later
          </Button>
          <Button size="sm">Upgrade</Button>
        </AlertAction>
      </Alert>
    </div>
  )
}
```

### Dismissible [#dismissible]

Set `dismissible` to add a close button. By default the alert manages its own visibility and animates out when closed. To remember the dismissal across visits, give it a `persistKey` — the choice is stored (in `localStorage` by default, or `sessionStorage` via `persistStorage`) and the alert stays hidden on return.

```tsx
import { Alert, AlertIcon, AlertTitle, AlertDescription } from '@appica/ui-react/alert'
import { CircleCheckFilled } from '@appica/icons-react'

export default function AlertDismissible() {
  return (
    <div className="w-full max-w-md">
      <Alert variant="success" dismissible>
        <AlertIcon>
          <CircleCheckFilled />
        </AlertIcon>
        <AlertTitle>Profile updated</AlertTitle>
        <AlertDescription>Your changes have been saved. You can dismiss this message.</AlertDescription>
      </Alert>
    </div>
  )
}
```

### Controlled [#controlled]

Drive visibility yourself with `open` + `onOpenChange` — for instance to show a success banner after a save, or to bring a dismissed alert back.

```tsx
'use client'

import * as React from 'react'
import { Alert, AlertIcon, AlertTitle, AlertDescription } from '@appica/ui-react/alert'
import { Button } from '@appica/ui-react/button'
import { InfoCircleFilled } from '@appica/icons-react'

export default function AlertControlled() {
  const [open, setOpen] = React.useState(true)

  return (
    <div className="flex w-full max-w-md flex-col items-center gap-4">
      <div className="w-full">
        <Alert variant="info" open={open} onOpenChange={setOpen} dismissible>
          <AlertIcon>
            <InfoCircleFilled />
          </AlertIcon>
          <AlertTitle>Good to know</AlertTitle>
          <AlertDescription>This banner is controlled. Dismiss it and bring it back below.</AlertDescription>
        </Alert>
      </div>
      {!open && (
        <Button variant="outline" size="sm" onClick={() => setOpen(true)}>
          Show alert
        </Button>
      )}
    </div>
  )
}
```

## RTL [#rtl]

Every Appica UI component supports right-to-left layouts out of the box. Set the `dir` attribute on a container (commonly your `<html>` element) so CSS logical properties resolve correctly, and wrap your tree in `DirectionProvider` so direction-aware behavior follows the same direction.

```tsx
import { DirectionProvider } from '@appica/ui-react/providers/direction-provider'

export default function RootLayout({ children }) {
  return (
    <html lang="ar" dir="rtl">
      <body>
        <DirectionProvider dir="rtl">{children}</DirectionProvider>
      </body>
    </html>
  )
}
```

The icon moves to the right, the dismiss button to the left, and the action row aligns to the start edge — all from CSS logical properties. For setup details and caveats, see the [RTL guide](/ui/docs/react/rtl).

<RtlPreview component="alert" />

## API reference [#api-reference]

### Alert [#alert]

The container. Renders a `<div role="alert">` and sets the variant, layout, and dismiss behavior.

| Prop             | <ColMinWidth width="210">Type</ColMinWidth>                                                       | Default     | <ColMinWidth width="220">Description</ColMinWidth>                                                 |
| ---------------- | ------------------------------------------------------------------------------------------------- | ----------- | -------------------------------------------------------------------------------------------------- |
| `variant`        | <Code>'default' \| 'primary' \| 'secondary' \| 'info' \| 'success' \| 'warning' \| 'error'</Code> | `'default'` | Color scheme; also drives the `AlertIcon` accent.                                                  |
| `layout`         | <Code>'block' \| 'inline'</Code>                                                                  | `'block'`   | Stack the parts (`block`) or flow them on one row when wide enough (`inline`).                     |
| `dismissible`    | `boolean`                                                                                         | `false`     | Render a close button that hides the alert (with an exit animation).                               |
| `open`           | `boolean`                                                                                         | —           | Controlled visibility. Pair with `onOpenChange`.                                                   |
| `onOpenChange`   | <Code>(open: boolean) => void</Code>                                                              | —           | Called when the alert is dismissed (with `false`).                                                 |
| `persistKey`     | `string`                                                                                          | —           | Remember the dismissal under this key so the alert stays hidden on return (uncontrolled).          |
| `persistStorage` | <Code>'local' \| 'session'</Code>                                                                 | `'local'`   | Which Web Storage backs `persistKey`.                                                              |
| `closeLabel`     | `string`                                                                                          | `'Dismiss'` | Accessible label for the close button.                                                             |
| `role`           | `AriaRole`                                                                                        | `'alert'`   | Live-region role announced by assistive tech. Use `'status'` for a polite, non-interruptive alert. |
| `className`      | `string`                                                                                          | —           | Extra classes on the container, merged via `tailwind-merge`.                                       |

Any other `<div>` attribute is forwarded to the container.

### AlertIcon [#alerticon]

A leading icon slot. Renders a `<span>` that colors its icon to match the variant.

| Prop        | Type        | Default | Description                                 |
| ----------- | ----------- | ------- | ------------------------------------------- |
| `children`  | `ReactNode` | —       | The icon to display.                        |
| `className` | `string`    | —       | Extra classes, merged via `tailwind-merge`. |

### AlertTitle [#alerttitle]

The headline. Renders an `<h5>` by default.

| Prop        | Type                              | Default | Description                                                  |
| ----------- | --------------------------------- | ------- | ------------------------------------------------------------ |
| `children`  | `ReactNode`                       | —       | The title text.                                              |
| `as`        | <Code>'h1' … 'h6' \| 'div'</Code> | `'h5'`  | Heading level, so the alert fits the page's heading outline. |
| `className` | `string`                          | —       | Extra classes, merged via `tailwind-merge`.                  |

### AlertDescription [#alertdescription]

The supporting body text. Renders a `<p>`.

| Prop        | Type        | Default | Description                                 |
| ----------- | ----------- | ------- | ------------------------------------------- |
| `children`  | `ReactNode` | —       | The body text.                              |
| `className` | `string`    | —       | Extra classes, merged via `tailwind-merge`. |

### AlertAction [#alertaction]

A trailing row for buttons. Renders a `<div>`.

| Prop        | Type        | Default | Description                                 |
| ----------- | ----------- | ------- | ------------------------------------------- |
| `children`  | `ReactNode` | —       | Action buttons.                             |
| `className` | `string`    | —       | Extra classes, merged via `tailwind-merge`. |

## Accessibility [#accessibility]

* `Alert` renders with `role="alert"`, so assistive tech announces its contents when it appears — keep the message concise and meaningful.
* Because `role="alert"` is an assertive live region, mount it only when there's something to announce; an alert present on every page load isn't announced on later changes.
* The dismiss button is a real `<button>` with an accessible name from `closeLabel` (default "Dismiss"); customise it when "Dismiss" is ambiguous.
* `AlertIcon` is decorative — convey meaning in the `AlertTitle`/`AlertDescription`, not the icon alone.
* The enter/exit animation is skipped when the user prefers reduced motion.
