Skip to content

Alert component

Alert surfaces contextual feedback inline with the content it relates to — a validation error under a form, a success message after a save, a warning banner at the top of a page. It renders with role="alert" so assistive technology announces it as soon as it appears, and unlike Toast it never leaves its place in the layout or auto-dismisses on its own.

Feedback22 propsAccessibility notes

Playground

Change a prop on the right and the preview updates. Switch to Code to copy what you see.

Recipes

Copy-paste patterns for the ways Alert actually gets used — each one a real, self-contained example.

Status colors

Colour maps to intent — success, warning, danger, info — and swaps the leading status icon to match.

<Alert color="success" title="Saved" description="Your changes are live." />
<Alert color="warning" title="Heads up" description="Your trial ends in 3 days." />
<Alert color="danger" title="Payment failed" description="Update your card to continue." />
<Alert color="info" title="Tip" description="You can theme this from one CSS file." />

Variants

solid, soft, and bordered — soft is the everyday inline notice; solid draws maximum attention.

<Alert variant="solid" color="primary" title="Solid" />
<Alert variant="soft" color="primary" title="Soft" />
<Alert variant="bordered" color="primary" title="Bordered" />

With actions

The actions slot holds buttons — a confirm/dismiss inline with the message.

<Alert
  color="warning"
  title="Unsaved changes"
  description="Leave without saving?"
  actions={
    <>
      <Button size="sm" variant="soft">Discard</Button>
      <Button size="sm" color="primary">Save</Button>
    </>
  }
/>

Dismissible

isClosable adds a × and, when uncontrolled, hides the alert on click — the standard dismissible banner.

<Alert
  color="info"
  title="New feature"
  description="Recipes are now on every component page."
  isClosable
/>

Custom icon

Override the default status icon with your own, or hide it entirely with hideIcon.

<Alert color="primary" icon={<SparkleIcon />} title="Pro tip" description="Set your brand ramp once." />
<Alert color="default" hideIcon title="Plain notice" description="No icon, just text." />

Feedback after an action

The most common place to reach for Alert is right after something happens — a form submits, a request fails, a background job finishes. Keep a small piece of state for whichever case applies, render the matching Alert conditionally, and pass isClosable with an onClose handler that clears that state so the user can dismiss it once they've read it.

const SaveFeedback = () => {
  const [status, setStatus] = useState<"success" | "error" | null>(null);

  async function handleSave() {
    try {
      await fetch("/api/profile", { method: "PATCH" });
      setStatus("success");
    } catch {
      setStatus("error");
    }
  }

  return (
    <div className="flex flex-col gap-3">
      {status === "success" && (
        <Alert
          color="success"
          title="Saved"
          description="Your profile changes were saved."
          isClosable
          onClose={() => setStatus(null)}
        />
      )}
      {status === "error" && (
        <Alert
          color="danger"
          title="Couldn't save"
          description="Something went wrong. Try again."
          isClosable
          onClose={() => setStatus(null)}
        />
      )}
      <Button onPress={handleSave} color="primary">Save changes</Button>
    </div>
  );
};

Variant and color together

variant controls density, color controls meaning, and they're independent — pick both for the emphasis a message actually needs. solid (the default) fills the background with the color and reads as the most urgent; soft uses a translucent tint of the color, a good default for messages living inside a form or card where a solid block would compete with the rest of the page; bordered keeps just a colored edge and barely-there background, for messages that should be noticeable but not shout.

The seven color values (default, primary, secondary, info, success, warning, danger) each drive the built-in status icon automatically, so picking a success or danger color doesn't require also picking an icon — Alert already knows which one fits.

<Alert variant="solid" color="danger" title="Failed" description="The upload could not complete." />
<Alert variant="soft" color="warning" title="Heads up" description="You have unsaved changes." />
<Alert variant="bordered" color="info" title="Note" description="This setting applies to new members only." />

Dismissible vs. persistent

isClosable adds a close button (and lets Escape dismiss it while it has focus) — reach for it on transient feedback like a save confirmation, where there's nothing left for the user to do but acknowledge it. Leave it off (the default) for a persistent alert the user needs to actually resolve, like a validation error still attached to an invalid field — closing it wouldn't fix the underlying problem, so removing the escape hatch keeps the message in front of them until the form is valid.

Alert supports both controlled and uncontrolled visibility. Pass isVisible yourself if you're already tracking the state elsewhere; otherwise just mount/unmount the Alert (as in the example above) and let onClose tell you when to unmount it.

Extra content: startContent, actions, endContent

Three optional slots sit around the title/description block for anything an inline text message alone can't cover. startContent renders above the icon/title/description row — useful for a small label or badge. actions renders directly below the description, for a button or two that respond to the alert ("Retry", "Undo", "View details"). endContent renders after actions, for something like a timestamp or a secondary link.

<Alert
  color="danger"
  title="Upload failed"
  description="The file exceeded the 10 MB limit."
  actions={
    <Button size="sm" variant="soft" color="danger" onPress={retry}>
      Try again
    </Button>
  }
  isClosable
  onClose={() => setShowError(false)}
/>

Custom and hidden icons

Every color role has a sensible default icon baked in, so most usage never needs to touch it. When it does: pass icon with any ReactNode to replace it outright, hideIcon to remove the icon (and its wrapper) entirely, or hideIconWrapper to keep the icon but drop the circular background behind it — handy when the icon itself already reads clearly without extra framing.

Props

The full public API for Alert. Every prop is stable and intentionally typed.

Content

title

ReactNode

default: —

Alert title.

description

ReactNode

default: —

Alert body content.

icon

ReactNode

default: —

Overrides the default color-derived status icon.

startContent

ReactNode

default: —

Content rendered before the title/description block.

endContent

ReactNode

default: —

Content rendered after the title/description block.

actions

ReactNode

default: —

Action buttons rendered below the description.

Appearance

color

"default" | "primary" | "secondary" | "info" | "success" | "warning" | "danger"

default: default

Semantic color, also picks the default status icon.

variant

"solid" | "soft" | "bordered"

default: solid

Visual style variant.

shadow

"none" | "xs" | "xs-sm" | "sm" | "md" | "lg"

default: none

Box-shadow depth.

radius

"none" | "xs" | "xs-sm" | "sm" | "md" | "lg" | "full"

default: md

Border radius.

size

"xs" | "xs-sm" | "sm" | "md" | "lg" | "xl"

default: md

Alert size.

Behavior & states

isVisible

boolean

default: —

Controlled visibility; uncontrolled defaults visible.

isClosable

boolean

default: false

Shows a close button.

hideIcon

boolean

default: false

Hides the status icon entirely.

hideIconWrapper

boolean

default: false

Hides the icon's background wrapper, keeping the icon itself.

closeButtonProps

Omit<ButtonHTMLAttributes<HTMLButtonElement>, "type">

default: —

Extra props forwarded to the close button.

Motion

disableAnimation

boolean

default: false

Disables the enter/exit animation.

Events

onClose

() => void

default: —

Called when the close button is pressed.

onVisibleChange

(isVisible: boolean) => void

default: —

Called whenever visibility changes.

Styling

classNames

Partial<Record<AlertSlot, string>>

default: —

Per-slot class overrides.

className

string

default: —

Class applied to the root element.

style

CSSProperties

default: —

Inline styles for the root element.

Accessibility

  • The root element carries role="alert", so screen readers announce new alerts as soon as they mount without the user needing to navigate to them.
  • When isClosable is true, the close button has a built-in aria-label of "Close" and responds to both a click and the Escape key while the alert has focus.
  • Color is never the only signal — pair it with a clear title/description, since color alone doesn't communicate anything to a screen-reader user or anyone with color-vision deficiency.

Best practices

  • Keep the title short and the description one sentence — Alert is for a quick status update, not an essay.
  • Use isClosable={false} for validation errors that are still attached to an invalid field, so the user resolves the actual problem instead of just dismissing the message.
  • Reach for variant="soft" inside forms and cards, where a solid block of color competes too hard with the surrounding content.
  • Avoid stacking more than two or three Alerts at once — if there are several unrelated issues, consider a single Alert with a list in the description instead.
  • For a message that should slide in, sit outside the document flow, and disappear on its own, use Toast instead — Alert stays inline and never auto-dismisses.