# Alert

> Present important page-level information or require a decision before work continues.

Source: https://www.honestui.com/docs/components/alert

```tsx
"use client"

import * as React from "react"

import {
  Alert,
  AlertDescription,
  AlertTitle,
} from "@/components/honest-ui/ui/alert"
import { Button } from "@/components/honest-ui/ui/button"
import { Field, FieldControl, FieldLabel } from "@/components/honest-ui/ui/field"
import { Form } from "@/components/honest-ui/ui/form"

export function AlertDemo() {
  const [email, setEmail] = React.useState("alex@example.com")
  const [sentTo, setSentTo] = React.useState<string | null>(null)

  return (
    <Form
      className="grid w-full max-w-sm gap-4 rounded-xl border bg-card p-5"
      onSubmit={(event) => {
        event.preventDefault()
        setSentTo(email)
      }}
    >
      <div className="space-y-1">
        <h3 className="font-medium">Invite a teammate</h3>
        <p className="text-sm text-muted-foreground">
          They will join the Design workspace as a member.
        </p>
      </div>
      <Field>
        <FieldLabel>Work email</FieldLabel>
        <FieldControl
          type="email"
          value={email}
          onChange={(event) => {
            setEmail(event.target.value)
            setSentTo(null)
          }}
          required
        />
      </Field>
      <Alert variant={sentTo ? "success" : "default"}>
        <AlertTitle>{sentTo ? "Invite sent" : "Before you invite"}</AlertTitle>
        <AlertDescription>
          {sentTo
            ? `${sentTo} can now join from the email invitation.`
            : "Invitations expire after seven days. You can revoke one at any time."}
        </AlertDescription>
      </Alert>
      <Button type="submit">{sentTo ? "Resend invite" : "Send invite"}</Button>
    </Form>
  )
}

```

## Overview [#overview]

Use an Alert to call attention to information that affects the current page or task: warnings about expiring payment methods, errors that need recovery, success confirmations worth keeping visible, and neutral guidance at the point of action.

Alerts live in the flow of the page, near the content they explain, and stay there until removed. That persistence is the dividing line from Toast: a toast confirms and disappears, while an alert remains as long as its condition does. When information must block all work until a person decides — deleting data, leaving with unsaved changes — use [Alert Dialog](/docs/components/alert-dialog) instead.

## Anatomy [#anatomy]

An Alert has a container, optional icon, title, description, and optional actions. The title names what happened in a few words. The description explains the consequence or what to do next. Actions sit in their own column on wide screens and drop below the text on narrow ones, so recovery is never more than one glance away.

When you render an icon as the first child, it occupies a fixed column aligned to the first line of text; the title and description shift to the second column automatically.

## Variants [#variants]

Choose the variant by meaning, not by color preference:

* `default` — neutral information with no state attached.
* `info` — guidance that changes how someone completes the current task.
* `success` — confirmation that completed work was saved or applied.
* `warning` — risk ahead: expiring cards, limits approaching, irreversible settings.
* `error` — something failed and needs recovery before the task can continue.

Each variant pairs a border and background tint with matching icon color. Because the tint uses low-alpha tokens over the card background, variants remain distinguishable in dark mode without vibrating against it.

## Behavior [#behavior]

Keep alerts close to the content they explain: a billing warning belongs on the billing page next to the payment method, not in a global banner where its context is lost. One alert per condition; when several conditions fire at once, consolidate them into a single message listing each item rather than stacking five boxes.

Render an Alert only while its condition holds. A stale success banner left on the page teaches people to ignore every other alert — see [Don't do this](#dont-do-this).

## Accessibility [#accessibility]

Every `Alert` renders `role="alert"`, so content inserted into the DOM inside it is announced immediately by screen readers, including failures reported after an async request completes. This urgency cuts both ways: reserve the component for information genuinely worth interrupting for, and note that an alert present at page load is typically not announced — sighted-only emphasis there is fine, but critical load-time context also needs a heading or focus target.

Do not rely on color alone. The variant color is always paired with your title and description text; add an icon when the extra cue helps scanning. Action buttons inside `AlertAction` are ordinary buttons, reachable by <kbd>Tab</kbd> with visible focus rings.

Text wraps within the container rather than truncating, so localized descriptions grow downward without clipping the action column. The grid uses logical properties and mirrors under `dir="rtl"`. Colors come from theme tokens, so all five variants hold WCAG-readable contrast in dark mode automatically.

## Installation [#installation]


  

  
    <CliBlock commands="[&#x22;alert&#x22;]" />
  

  
    
      
        Import the following variables into your CSS file
      

      ```css
      @theme inline {
        --color-destructive-foreground: var(--destructive-foreground);
        --color-info: var(--info);
        --color-info-foreground: var(--info-foreground);
        --color-success: var(--success);
        --color-success-foreground: var(--success-foreground);
        --color-warning: var(--warning);
        --color-warning-foreground: var(--warning-foreground);
      }

      :root {
        --destructive-foreground: oklch(0.704 0.191 22.216);
        --info: oklch(0.623 0.214 259.815);
        --info-foreground: oklch(0.707 0.165 254.624);
        --success: oklch(0.696 0.17 162.48);
        --success-foreground: oklch(0.765 0.177 163.223);
        --warning: oklch(0.769 0.188 70.08);
        --warning-foreground: oklch(0.828 0.189 84.429);
      }

      .dark {
        --destructive-foreground: oklch(0.704 0.191 22.216);
        --info: oklch(0.623 0.214 259.815);
        --info-foreground: oklch(0.707 0.165 254.624);
        --success: oklch(0.696 0.17 162.48);
        --success-foreground: oklch(0.765 0.177 163.223);
        --warning: oklch(0.769 0.188 70.08);
        --warning-foreground: oklch(0.828 0.189 84.429);
      }
      ```

      
        Install the following dependencies:
      

      ```bash
      npm install @base-ui-components/react
      ```

      
        Copy and paste the following code into your project.
      

      ### components/ui/alert.tsx

```tsx
"use client"

import * as React from "react"
import { AlertDialog as AlertDialogPrimitive } from "@base-ui-components/react/alert-dialog"
import { cva, type VariantProps } from "class-variance-authority"

import { cn } from "@/lib/utils"

const alertVariants = cva(
  "relative grid w-full items-start gap-x-2 gap-y-0.5 rounded-xl border px-3.5 py-3 text-sm text-card-foreground has-data-[slot=alert-action]:grid-cols-[1fr_auto] has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-[>svg]:gap-x-2 has-[>svg]:has-data-[slot=alert-action]:grid-cols-[calc(var(--spacing)*4)_1fr_auto] [&>svg]:h-[1lh] [&>svg]:w-4",
  {
    variants: {
      variant: {
        default:
          "bg-transparent dark:bg-input/32 [&>svg]:text-muted-foreground",
        info: "border-info/32 bg-info/4 [&>svg]:text-info",
        success: "border-success/32 bg-success/4 [&>svg]:text-success",
        warning: "border-warning/32 bg-warning/4 [&>svg]:text-warning",
        error:
          "border-destructive/32 bg-destructive/4 [&>svg]:text-destructive",
      },
    },
    defaultVariants: {
      variant: "default",
    },
  }
)

function Alert({
  className,
  variant,
  ...props
}: React.ComponentProps<"div"> & VariantProps<typeof alertVariants>) {
  return (
    <div
      data-slot="alert"
      role="alert"
      className={cn(alertVariants({ variant }), className)}
      {...props}
    />
  )
}

function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="alert-title"
      className={cn("font-medium [svg~&]:col-start-2", className)}
      {...props}
    />
  )
}

function AlertDescription({
  className,
  ...props
}: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="alert-description"
      className={cn(
        "flex flex-col gap-2.5 text-muted-foreground [svg~&]:col-start-2",
        className
      )}
      {...props}
    />
  )
}

function AlertAction({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="alert-action"
      className={cn(
        "flex gap-1 max-sm:col-start-2 max-sm:mt-2 sm:row-start-1 sm:row-end-3 sm:self-center sm:[[data-slot=alert-description]~&]:col-start-2 sm:[[data-slot=alert-title]~&]:col-start-2 sm:[svg~&]:col-start-2 sm:[svg~[data-slot=alert-description]~&]:col-start-3 sm:[svg~[data-slot=alert-title]~&]:col-start-3",
        className
      )}
      {...props}
    />
  )
}

function AlertDialog(props: AlertDialogPrimitive.Root.Props) {
  return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />
}

function AlertDialogTrigger(props: AlertDialogPrimitive.Trigger.Props) {
  return (
    <AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
  )
}

function AlertDialogPortal(props: AlertDialogPrimitive.Portal.Props) {
  return <AlertDialogPrimitive.Portal {...props} />
}

function AlertDialogBackdrop({
  className,
  ...props
}: AlertDialogPrimitive.Backdrop.Props) {
  return (
    <AlertDialogPrimitive.Backdrop
      data-slot="alert-dialog-backdrop"
      className={cn(
        "fixed inset-0 z-[var(--hui-z-index-portal)] bg-black/32 backdrop-blur-sm transition-all duration-200 ease-out data-ending-style:opacity-0 data-starting-style:opacity-0",
        className
      )}
      {...props}
    />
  )
}

function AlertDialogPopup({
  className,
  ...props
}: AlertDialogPrimitive.Popup.Props) {
  return (
    <AlertDialogPortal>
      <AlertDialogBackdrop />
      <div className="fixed inset-0 z-[var(--hui-z-index-portal)]">
        <div className="flex h-[100dvh] flex-col items-center overflow-hidden pt-6 max-sm:before:flex-1 sm:overflow-y-auto sm:p-4 sm:before:basis-[20vh] sm:after:flex-1">
          <AlertDialogPrimitive.Popup
            data-slot="alert-dialog-popup"
            className={cn(
              "row-start-2 grid w-full min-w-0 origin-top gap-0 border bg-popover bg-clip-padding p-0 text-popover-foreground shadow-lg transition-[scale,opacity,translate] duration-200 ease-in-out will-change-transform data-ending-style:opacity-0 data-starting-style:opacity-0 max-sm:overflow-y-auto max-sm:border-none max-sm:opacity-[calc(1-min(var(--nested-dialogs),1))] max-sm:data-ending-style:translate-y-4 max-sm:data-starting-style:translate-y-4 sm:max-w-lg sm:-translate-y-[calc(1.25rem*var(--nested-dialogs))] sm:scale-[calc(1-0.1*var(--nested-dialogs))] sm:rounded-2xl sm:data-ending-style:scale-98 sm:data-starting-style:scale-98 dark:bg-clip-border",
              "relative before:pointer-events-none before:absolute before:inset-0 before:shadow-[0_1px_--theme(--color-black/4%)] max-sm:before:hidden sm:before:rounded-[calc(var(--radius-2xl)-1px)] sm:data-nested:data-ending-style:translate-y-8 sm:data-nested:data-starting-style:translate-y-8 dark:before:shadow-[0_-1px_--theme(--color-white/8%)]",
              className
            )}
            {...props}
          />
        </div>
      </div>
    </AlertDialogPortal>
  )
}

function AlertDialogHeader({
  className,
  ...props
}: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="alert-dialog-header"
      className={cn(
        "flex flex-col gap-2 border-b-0 p-[var(--hui-space-7)] text-center [&:has(+_[data-slot=alert-dialog-body])]:pb-[var(--hui-space-5)] sm:text-left",
        className
      )}
      {...props}
    />
  )
}

function AlertDialogBody({
  className,
  ...props
}: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="alert-dialog-body"
      className={cn(
        "px-[var(--hui-space-7)] pb-[var(--hui-space-5)] first:p-[var(--hui-space-7)]",
        className
      )}
      {...props}
    />
  )
}

function AlertDialogFooter({
  className,
  ...props
}: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="alert-dialog-footer"
      className={cn(
        "flex flex-col-reverse gap-2 border-t-0 px-[var(--hui-space-7)] pb-[var(--hui-space-7)] sm:flex-row sm:justify-end",
        className
      )}
      {...props}
    />
  )
}

function AlertDialogTitle({
  className,
  ...props
}: AlertDialogPrimitive.Title.Props) {
  return (
    <AlertDialogPrimitive.Title
      data-slot="alert-dialog-title"
      className={cn("text-lg font-semibold", className)}
      {...props}
    />
  )
}

function AlertDialogDescription({
  className,
  ...props
}: AlertDialogPrimitive.Description.Props) {
  return (
    <AlertDialogPrimitive.Description
      data-slot="alert-dialog-description"
      className={cn("text-sm text-muted-foreground", className)}
      {...props}
    />
  )
}

function AlertDialogClose(props: AlertDialogPrimitive.Close.Props) {
  return (
    <AlertDialogPrimitive.Close data-slot="alert-dialog-close" {...props} />
  )
}

export {
  Alert,
  AlertTitle,
  AlertDescription,
  AlertAction,
  AlertDialog,
  AlertDialogPortal,
  AlertDialogBackdrop,
  AlertDialogBackdrop as AlertDialogOverlay,
  AlertDialogTrigger,
  AlertDialogPopup,
  AlertDialogPopup as AlertDialogContent,
  AlertDialogHeader,
  AlertDialogBody,
  AlertDialogFooter,
  AlertDialogTitle,
  AlertDialogDescription,
  AlertDialogClose,
}

```

      
        Update the import paths to match your project setup.
      
    
  


## Usage [#usage]

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

```tsx
> 
  <TriangleAlertIcon />
  <AlertTitle>Payment method expires soon</AlertTitle>
  <AlertDescription>
    Update the card on file before June 14 to keep automations running.
  </AlertDescription>
  <AlertAction>
    <Button variant="secondary" size="sm">Update card</Button>
  </AlertAction>

```

The same file also exports the modal family — `AlertDialog`, `AlertDialogTrigger`, `AlertDialogPopup`, and related parts. Those follow Base UI's Alert Dialog semantics instead; see [Alert Dialog](/docs/components/alert-dialog) for when a blocking decision is appropriate and how it differs from Dialog.

## Don't do this [#dont-do-this]

### Marketing decoration [#marketing-decoration]

```tsx
// Bad
> 
  <AlertTitle>🔥 Summer sale ends tonight!</AlertTitle>
  <AlertDescription>Use code SUMMER for 20% off.</AlertDescription>

```

```tsx
// Good
<div className="rounded-xl border bg-card p-3.5 text-sm">
  Use code <strong>SUMMER</strong> for 20% off before midnight.
</div>
```

Every red box trains people a little more to skim past red boxes. When promotions wear error styling, real errors lose the urgency they depend on — and screen-reader users get "alert" announced for an advertisement. Style marketing content neutrally and save the component for conditions that affect the task.

### Warnings without a consequence [#warnings-without-a-consequence]

```tsx
// Bad
> 
  <AlertTitle>Warning!</AlertTitle>
  <AlertDescription>Please review your settings.</AlertDescription>

```

```tsx
// Good
> 
  <AlertTitle>Deploys paused for this repository</AlertTitle>
  <AlertDescription>
    Billing is suspended. Restore payment within 7 days to keep deploy history.
  </AlertDescription>

```

"Warning" announces that something might be wrong somewhere, which helps no one deciding what to do next. Name the affected thing in the title and state what changes if nothing happens. If you cannot write the consequence, the alert probably is not needed yet.

### One alert per failure [#one-alert-per-failure]

```tsx
// Bad
> <AlertTitle>Name is missing.</AlertTitle>
> <AlertTitle>Email is invalid.</AlertTitle>
> <AlertTitle>Password is too short.</AlertTitle>
```

```tsx
// Good
> 
  <AlertTitle>Fix 3 fields before saving</AlertTitle>
  <AlertDescription>
    <ul>
      <li>Name is required.</li>
      <li>Email must include an @.</li>
      <li>Password must be at least 12 characters.</li>
    </ul>
  </AlertDescription>

```

A stack of near-identical boxes shouts the same interruption three times, triples the visual noise, and pushes the form itself off screen. Consolidate into one alert with a list, and keep per-field messages next to their fields where correction happens.

## Examples [#examples]

Each example places the alert inside the task that produces it, including the action, result, and recovery path where they matter.

### With Icon [#with-icon]

Generate a new set of recovery codes and see how the alert explains the consequence before and after the action.

```tsx
"use client"

import * as React from "react"
import { Info as InfoIcon } from "honestui/icons"

import {
  Alert,
  AlertDescription,
  AlertTitle,
} from "@/components/honest-ui/ui/alert"
import { Button } from "@/components/honest-ui/ui/button"

export function AlertWithIcon() {
  const [generated, setGenerated] = React.useState(false)

  return (
    <section className="grid w-full max-w-sm gap-4 rounded-xl border bg-card p-5">
      <div className="space-y-1">
        <h3 className="font-medium">Recovery codes</h3>
        <p className="text-sm text-muted-foreground">
          Use a recovery code if you lose access to your authenticator.
        </p>
      </div>
      <Alert>
        <InfoIcon />
        <AlertTitle>
          {generated ? "New codes are ready" : "Keep your codes private"}
        </AlertTitle>
        <AlertDescription>
          {generated
            ? "Your previous codes no longer work. Store the new set somewhere safe."
            : "Generating a new set will invalidate every code you saved before."}
        </AlertDescription>
      </Alert>
      <Button onClick={() => setGenerated((current) => !current)}>
        {generated ? "Generate another set" : "Generate new codes"}
      </Button>
    </section>
  )
}

```

### With Icon and Action Buttons [#with-icon-and-action-buttons]

Turn on two-step verification, defer it, or return to the setup from the same account-security workflow.

```tsx
"use client"

import * as React from "react"
import {
  CircleCheck as CircleCheckIcon,
  Info as InfoIcon,
  TriangleAlert as TriangleAlertIcon,
} from "honestui/icons"

import {
  Alert,
  AlertAction,
  AlertDescription,
  AlertTitle,
} from "@/components/honest-ui/ui/alert"
import { Button } from "@/components/honest-ui/ui/button"

export function AlertWithIconAction() {
  const [status, setStatus] = React.useState<"review" | "later" | "secured">(
    "review"
  )
  const StatusIcon =
    status === "secured"
      ? CircleCheckIcon
      : status === "later"
        ? TriangleAlertIcon
        : InfoIcon

  return (
    <section className="grid w-full max-w-lg gap-4 rounded-xl border bg-card p-5">
      <div className="flex items-center justify-between gap-4">
        <div className="space-y-1">
          <h3 className="font-medium">Account security</h3>
          <p className="text-sm text-muted-foreground">Two-step verification</p>
        </div>
        <span className="text-sm font-medium">
          {status === "secured" ? "On" : "Off"}
        </span>
      </div>
      <Alert
        variant={
          status === "secured"
            ? "success"
            : status === "later"
              ? "warning"
              : "info"
        }
      >
        <StatusIcon />
        <AlertTitle>
          {status === "secured"
            ? "Two-step verification is on"
            : status === "later"
              ? "Two-step verification is still off"
              : "Protect your account"}
        </AlertTitle>
        <AlertDescription>
          {status === "secured"
            ? "New devices now require an additional sign-in step."
            : status === "later"
              ? "You can return to this setup whenever you are ready."
              : "Require a second step when someone signs in on a new device."}
        </AlertDescription>
        <AlertAction>
          {status !== "secured" && (
            <Button
              variant="ghost"
              size="xs"
              onClick={() =>
                setStatus(status === "later" ? "review" : "later")
              }
            >
              {status === "later" ? "Review setup" : "Later"}
            </Button>
          )}
          {status !== "later" && (
            <Button
              size="xs"
              onClick={() =>
                setStatus(status === "secured" ? "review" : "secured")
              }
            >
              {status === "secured" ? "Reset example" : "Turn on"}
            </Button>
          )}
        </AlertAction>
      </Alert>
    </section>
  )
}

```

### Info Alert [#info-alert]

Give neutral guidance at the point where it changes how someone completes a form.

```tsx
"use client"

import * as React from "react"
import { Info as InfoIcon } from "honestui/icons"

import {
  Alert,
  AlertDescription,
  AlertTitle,
} from "@/components/honest-ui/ui/alert"
import { Button } from "@/components/honest-ui/ui/button"
import { Field, FieldControl, FieldLabel } from "@/components/honest-ui/ui/field"
import { Form } from "@/components/honest-ui/ui/form"

export function AlertInfo() {
  const [ready, setReady] = React.useState(false)

  return (
    <Form
      className="grid w-full max-w-sm gap-4 rounded-xl border bg-card p-5"
      onSubmit={(event) => {
        event.preventDefault()
        setReady(true)
      }}
    >
      <div className="space-y-1">
        <h3 className="font-medium">Billing address</h3>
        <p className="text-sm text-muted-foreground">
          Used for invoices and tax calculations.
        </p>
      </div>
      <Alert variant={ready ? "success" : "info"}>
        <InfoIcon />
        <AlertTitle>
          {ready
            ? "Address ready for review"
            : "Use the address on your payment method"}
        </AlertTitle>
        <AlertDescription>
          {ready
            ? "Check the address and total on the next step before you pay."
            : "A mismatch may cause your bank to decline the payment."}
        </AlertDescription>
      </Alert>
      <Field>
        <FieldLabel>Postal code</FieldLabel>
        <FieldControl name="postal-code" autoComplete="postal-code" />
      </Field>
      <Button
        type={ready ? "button" : "submit"}
        onClick={ready ? () => setReady(false) : undefined}
      >
        {ready ? "Edit address" : "Continue to review"}
      </Button>
    </Form>
  )
}

```

### Success Alert [#success-alert]

Confirm a saved profile change while keeping the edited field and next state in view.

```tsx
"use client"

import * as React from "react"
import { CircleCheck as CircleCheckIcon } from "honestui/icons"

import {
  Alert,
  AlertDescription,
  AlertTitle,
} from "@/components/honest-ui/ui/alert"
import { Button } from "@/components/honest-ui/ui/button"
import { Field, FieldControl, FieldLabel } from "@/components/honest-ui/ui/field"
import { Form } from "@/components/honest-ui/ui/form"

export function AlertSuccess() {
  const [saved, setSaved] = React.useState(true)

  return (
    <Form
      className="grid w-full max-w-sm gap-4 rounded-xl border bg-card p-5"
      onSubmit={(event) => {
        event.preventDefault()
        setSaved(true)
      }}
    >
      <div className="space-y-1">
        <h3 className="font-medium">Profile</h3>
        <p className="text-sm text-muted-foreground">
          This name appears to everyone in your workspace.
        </p>
      </div>
      <Field>
        <FieldLabel>Display name</FieldLabel>
        <FieldControl
          defaultValue="Alex Morgan"
          onChange={() => setSaved(false)}
        />
      </Field>
      {saved && (
        <Alert variant="success">
          <CircleCheckIcon />
          <AlertTitle>Profile saved</AlertTitle>
          <AlertDescription>
            Your updated name is now visible across the workspace.
          </AlertDescription>
        </Alert>
      )}
      <Button
        type={saved ? "button" : "submit"}
        onClick={saved ? () => setSaved(false) : undefined}
      >
        {saved ? "Edit profile" : "Save changes"}
      </Button>
    </Form>
  )
}

```

### Warning Alert [#warning-alert]

Warn about an expiring payment method and show what changes after it is replaced.

```tsx
"use client"

import * as React from "react"
import { TriangleAlert as TriangleAlertIcon } from "honestui/icons"

import {
  Alert,
  AlertDescription,
  AlertTitle,
} from "@/components/honest-ui/ui/alert"
import { Button } from "@/components/honest-ui/ui/button"

export function AlertWarning() {
  const [updated, setUpdated] = React.useState(false)

  return (
    <section className="grid w-full max-w-sm gap-4 rounded-xl border bg-card p-5">
      <div className="space-y-1">
        <h3 className="font-medium">Payment method</h3>
        <p className="text-sm text-muted-foreground">
          Visa ending in 4242 · Expires this month
        </p>
      </div>
      <Alert variant={updated ? "success" : "warning"}>
        <TriangleAlertIcon />
        <AlertTitle>
          {updated ? "Payment method updated" : "Card expires soon"}
        </AlertTitle>
        <AlertDescription>
          {updated
            ? "Future invoices will use the replacement card."
            : "Replace this card before your next invoice to avoid an interrupted subscription."}
        </AlertDescription>
      </Alert>
      <Button onClick={() => setUpdated((current) => !current)}>
        {updated ? "Reset example" : "Replace card"}
      </Button>
    </section>
  )
}

```

### Error Alert [#error-alert]

Preserve the failed value, explain the valid format, and let the user recover in place.

```tsx
"use client"

import * as React from "react"
import { CircleAlert as CircleAlertIcon } from "honestui/icons"

import {
  Alert,
  AlertDescription,
  AlertTitle,
} from "@/components/honest-ui/ui/alert"
import { Button } from "@/components/honest-ui/ui/button"
import { Field, FieldControl, FieldLabel } from "@/components/honest-ui/ui/field"
import { Form } from "@/components/honest-ui/ui/form"

export function AlertError() {
  const [url, setUrl] = React.useState("example.com/webhook")
  const [connected, setConnected] = React.useState(false)

  const isValid = url.startsWith("https://")

  return (
    <Form
      className="grid w-full max-w-sm gap-4 rounded-xl border bg-card p-5"
      onSubmit={(event) => {
        event.preventDefault()
        setConnected(isValid)
      }}
    >
      <div className="space-y-1">
        <h3 className="font-medium">Webhook endpoint</h3>
        <p className="text-sm text-muted-foreground">
          Send workspace events to your server.
        </p>
      </div>
      <Field invalid={!isValid}>
        <FieldLabel>Endpoint URL</FieldLabel>
        <FieldControl
          value={url}
          onChange={(event) => {
            setUrl(event.target.value)
            setConnected(false)
          }}
          aria-describedby="webhook-status"
        />
      </Field>
      <Alert variant={connected ? "success" : "error"} id="webhook-status">
        <CircleAlertIcon />
        <AlertTitle>
          {connected ? "Webhook connected" : "Connection failed"}
        </AlertTitle>
        <AlertDescription>
          {connected
            ? "The endpoint is ready to receive workspace events."
            : "Enter a secure URL that starts with https://, then try again."}
        </AlertDescription>
      </Alert>
      <Button type="submit">
        {connected ? "Test again" : "Test connection"}
      </Button>
    </Form>
  )
}

```

### Standalone notice [#standalone-notice]

A compact warning with icon and no actions — the smallest complete alert.

```tsx
import { CreditCard as CreditCardIcon } from "honestui/icons"

import {
  Alert,
  AlertDescription,
  AlertTitle,
} from "@/components/honest-ui/ui/alert"

export function AlertBillingNotice() {
  return (
    <Alert variant="warning" className="max-w-md">
      <CreditCardIcon />
      <AlertTitle>Payment method expires soon</AlertTitle>
      <AlertDescription>
        Update the card on file before June 14 to keep automations running.
      </AlertDescription>
    </Alert>
  )
}

```

## API reference [#api-reference]

The inline family accepts native element props plus:

| Part               | Renders            | Props                                                                           |
| ------------------ | ------------------ | ------------------------------------------------------------------------------- |
| `Alert`            | `div role="alert"` | `variant`: `default`, `info`, `success`, `warning`, `error` (default `default`) |
| `AlertTitle`       | `div`              | Native div props                                                                |
| `AlertDescription` | `div`              | Native div props                                                                |
| `AlertAction`      | `div`              | Native div props; wrap buttons or links                                         |

`Alert` renders `role="alert"` unconditionally, which drives the announcement behavior described above. Render it only when its content should be announced or emphasized; use plain containers for decorative callouts.

The modal parts (`AlertDialog` and children) forward Base UI Alert Dialog props and are documented on the [Alert Dialog page](/docs/components/alert-dialog).
