# Alert

Displays a callout for user attention.

```tsx
import * as stylex from "@stylexjs/stylex"
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
import { VStack } from "@/components/ui/stack"
import { CircleCheck, Info } from "lucide-react"

const styles = stylex.create({
  stack: { width: "100%", maxWidth: "28rem" },
})

export default function AlertDemo() {
  return (
    <VStack gap={4} xstyle={styles.stack}>
      <Alert>
        <CircleCheck />
        <AlertTitle>Payment successful</AlertTitle>
        <AlertDescription>
          Your payment of $29.99 has been processed. A receipt has been sent to your email address.
        </AlertDescription>
      </Alert>
      <Alert>
        <Info />
        <AlertTitle>New feature available</AlertTitle>
        <AlertDescription>
          We&apos;ve added dark mode support. You can enable it in your account settings.
        </AlertDescription>
      </Alert>
    </VStack>
  )
}
```

## Installation

1. Install the following dependencies:

   ```bash
   npm install @base-ui/react @stylexjs/stylex clsx
   ```

2. Set up the token layer and the StyleX compiler, if you have not already. See
   [Installation](https://carbon.style/docs/installation). The alert also needs `interop.css`, which
   places the icon and sizes it.

3. Copy and paste the following code into your project.

   ```tsx title="components/ui/alert.tsx"
   "use client"

   import { useRender } from "@base-ui/react/use-render"
   import * as stylex from "@stylexjs/stylex"
   import type { StyleXStyles } from "@stylexjs/stylex"
   import { clsx } from "clsx"

   import { breakpoints } from "@/theme/breakpoints.stylex"
   import { color, leading, radius, shadow, space, text } from "@/theme/tokens.stylex"

   const styles = stylex.create({
     root: {
       display: "grid",
       gridTemplateColumns: "auto 1fr auto",
       rowGap: space.s0_5,
       width: "100%",
       paddingInline: space.s2_5,
       paddingBlock: space.s2,
       borderRadius: radius.lg,
       borderWidth: 1,
       borderStyle: "solid",
       backgroundColor: color.card,
       boxShadow: shadow.xs,
       textAlign: "start",
       fontSize: text.sm,
       lineHeight: leading.sm,
       "--carbon-icon-size": space.s4,
     },
     title: { gridColumn: "2", fontWeight: 500 },
     description: {
       gridColumn: "2",
       color: "var(--carbon-alert-description)",
       textWrap: { default: "balance", [breakpoints.md]: "pretty" },
     },
     action: {
       gridColumn: "3",
       gridRowStart: "1",
       gridRowEnd: "span 2",
       alignSelf: "start",
       marginInlineStart: space.s2,
     },
   })

   const variants = stylex.create({
     default: {
       color: color.cardForeground,
       "--carbon-alert-description": color.mutedForeground,
     },
     destructive: {
       color: color.destructive,
       "--carbon-alert-description": `color-mix(in oklab, ${color.destructive} 90%, transparent)`,
     },
   })

   const alertStyles = { base: styles.root, variants }

   type AlertVariant = keyof typeof variants

   type Overrides = { xstyle?: StyleXStyles; className?: string }

   type AlertProps = useRender.ComponentProps<"div"> & Overrides & { variant?: AlertVariant }

   function Alert({
     render,
     ref,
     style,
     variant = "default",
     xstyle,
     className,
     ...props
   }: AlertProps) {
     const sx = stylex.props(styles.root, variants[variant] ?? variants.default, xstyle)
     return useRender({
       defaultTagName: "div",
       render,
       ref,
       props: {
         "data-slot": "alert",
         "data-variant": variant,
         role: "alert",
         ...sx,
         ...props,
         className: clsx("carbon-icons", sx.className, className),
         style: { ...sx.style, ...style },
       },
     })
   }

   function AlertTitle({
     render,
     ref,
     style,
     xstyle,
     className,
     ...props
   }: useRender.ComponentProps<"div"> & Overrides) {
     const sx = stylex.props(styles.title, xstyle)
     return useRender({
       defaultTagName: "div",
       render,
       ref,
       props: {
         "data-slot": "alert-title",
         ...sx,
         ...props,
         className: clsx(sx.className, className),
         style: { ...sx.style, ...style },
       },
     })
   }

   function AlertDescription({
     render,
     ref,
     style,
     xstyle,
     className,
     ...props
   }: useRender.ComponentProps<"div"> & Overrides) {
     const sx = stylex.props(styles.description, xstyle)
     return useRender({
       defaultTagName: "div",
       render,
       ref,
       props: {
         "data-slot": "alert-description",
         ...sx,
         ...props,
         className: clsx(sx.className, className),
         style: { ...sx.style, ...style },
       },
     })
   }

   function AlertAction({
     render,
     ref,
     style,
     xstyle,
     className,
     ...props
   }: useRender.ComponentProps<"div"> & Overrides) {
     const sx = stylex.props(styles.action, xstyle)
     return useRender({
       defaultTagName: "div",
       render,
       ref,
       props: {
         "data-slot": "alert-action",
         ...sx,
         ...props,
         className: clsx(sx.className, className),
         style: { ...sx.style, ...style },
       },
     })
   }

   export { Alert, AlertAction, AlertDescription, AlertTitle, alertStyles, type AlertVariant }
   ```

4. Update the import paths to match your project setup.

## Usage

```tsx
import { Alert, AlertAction, AlertDescription, AlertTitle } from "@/components/ui/alert"
```

```tsx
<Alert>
  <InfoIcon />
  <AlertTitle>Heads up!</AlertTitle>
  <AlertDescription>You can add components to your app using the cli.</AlertDescription>
  <AlertAction>
    <Button variant="outline">Enable</Button>
  </AlertAction>
</Alert>
```

## Composition

```text
Alert
├── Icon
├── AlertTitle
├── AlertDescription
└── AlertAction
```

The icon is any `svg` passed as a direct child. The alert is a three-column
grid, and `interop.css` places the icon in the first column and the action in
the last. Both columns collapse to nothing when empty.

## Basic

A basic alert with an icon, title and description.

```tsx
import * as stylex from "@stylexjs/stylex"
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
import { CircleCheck } from "lucide-react"

const styles = stylex.create({
  alert: { maxWidth: "28rem" },
})

export default function AlertBasic() {
  return (
    <Alert xstyle={styles.alert}>
      <CircleCheck />
      <AlertTitle>Account updated successfully</AlertTitle>
      <AlertDescription>
        Your profile information has been saved. Changes will be reflected immediately.
      </AlertDescription>
    </Alert>
  )
}
```

## Destructive

Use `variant="destructive"` to create a destructive alert.

```tsx
import * as stylex from "@stylexjs/stylex"
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
import { CircleAlert } from "lucide-react"

const styles = stylex.create({
  alert: { maxWidth: "28rem" },
})

export default function AlertDestructive() {
  return (
    <Alert variant="destructive" xstyle={styles.alert}>
      <CircleAlert />
      <AlertTitle>Payment failed</AlertTitle>
      <AlertDescription>
        Your payment could not be processed. Please check your payment method and try again.
      </AlertDescription>
    </Alert>
  )
}
```

## Action

Use `AlertAction` to add a button or other action element to the alert.

```tsx
import * as stylex from "@stylexjs/stylex"
import { Alert, AlertAction, AlertDescription, AlertTitle } from "@/components/ui/alert"
import { Button } from "@/components/ui/button"

const styles = stylex.create({
  alert: { maxWidth: "28rem" },
})

export default function AlertActionDemo() {
  return (
    <Alert xstyle={styles.alert}>
      <AlertTitle>Dark mode is now available</AlertTitle>
      <AlertDescription>Enable it under your profile settings to get started.</AlertDescription>
      <AlertAction>
        <Button size="xs">Enable</Button>
      </AlertAction>
    </Alert>
  )
}
```

## Custom colors

Pass `xstyle` to change the border, background and text colors. Set
`--carbon-alert-description` in the same block to recolor the description,
which otherwise reads the variant's muted color.

```tsx
import * as stylex from "@stylexjs/stylex"
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
import { color } from "@/theme/tokens.stylex"
import { TriangleAlert } from "lucide-react"

const styles = stylex.create({
  alert: {
    maxWidth: "28rem",
    borderColor: color.calloutWarnBorder,
    backgroundColor: color.calloutWarnBg,
    color: color.calloutWarnAccent,
    "--carbon-alert-description": color.calloutWarnAccent,
  },
})

export default function AlertColors() {
  return (
    <Alert xstyle={styles.alert}>
      <TriangleAlert />
      <AlertTitle>Your subscription will expire in 3 days.</AlertTitle>
      <AlertDescription>
        Renew now to avoid service interruption or upgrade to a paid plan to continue using the
        service.
      </AlertDescription>
    </Alert>
  )
}
```

## API reference

Pass `render` to replace a part's element or compose it with another component.

### Alert

Renders a `div` with `role="alert"`. Every part also takes `xstyle` and
`className`.

| Prop      | Type                         | Default     |
| --------- | ---------------------------- | ----------- |
| `variant` | `"default" \| "destructive"` | `"default"` |

### alertStyles

The style map behind the component, exported so you can apply the same styles
to any element.

| Key        | Description                                |
| ---------- | ------------------------------------------ |
| `base`     | The grid, padding, border and type         |
| `variants` | One entry per `variant`, keyed by its name |

### Data attributes

| Attribute                       | On              | Effect                                        |
| ------------------------------- | --------------- | --------------------------------------------- |
| `data-slot="alert"`             | the root        | Where `interop.css` keys the icon's grid slot |
| `data-variant`                  | the root        | Reflects the `variant` prop                   |
| `data-slot="alert-title"`       | the title       | Links inside are underlined by `interop.css`  |
| `data-slot="alert-description"` | the description | Links inside are underlined by `interop.css`  |
| `data-slot="alert-action"`      | the action      | Targets the action from a parent              |

### CSS variables

| Variable                     | On       | Effect                                                        |
| ---------------------------- | -------- | ------------------------------------------------------------- |
| `--carbon-alert-description` | the root | The description's color. Set by the variant, read by the part |
