State & Feedback Systems

Alert Callout

An alert callout React component in five semantic variants that fades up on entry, collapses by height when dismissed so content below slides into place, and gives its icon a small pop when live content updates.

The callout you reach for at the top of forms, settings pages and dashboards. variant comes in default, info, success, warning and destructive, each with its own leading icon, 3px accent band and colours; it holds a title, a description and an action slot. With dismissible a close button appears in the top-right corner — dismissing is not an instant disappearance: the callout fades out while its height and margins collapse to 0, so the content below slides up into place, and only then does it unmount and call onDismiss. With live on, the icon pops once whenever the title or description changes, signalling that the callout was just updated.

Bring this into your project

Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.

npx webberui@latest add alert-callout.en

New project or installation trouble? Start here →

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

150
180
Active edited usageDefault props
<AlertCallout/>

The complete example includes the preview layout and data. Install the component first, then paste this file into your project.

Installation

npx webberui@latest add https://webberui.com/r/alert-callout.en.json

Or, once registries are configured in components.json, install it as @webberui/alert-callout.

Usage

import { AlertCallout } from "@/components/ui/alert-callout";

<AlertCallout
  className="mb-3"
  variant="warning"
  title="Your payment method expires on November 30"
  description="Auto-renewal will stop after that date, so update your card details first."
  action={<button type="button">Update payment method</button>}
/>

<AlertCallout
  className="mb-3"
  variant="success"
  title="Changes saved"
  description={`Saved at ${savedAt}`}
  dismissible
  live
  onDismiss={() => console.log("dismissed")}
/>

Props

PropTypeDefaultDescription
variant"default" | "info" | "success" | "warning" | "destructive""default"Semantic variant; controls the leading icon, accent band and colours
titleReactNode—Title text
descriptionReactNode—Description content
iconReactNode | nullper variantOverrides the default icon; pass null to hide it
actionReactNode—Action slot (e.g. a "Refresh" button), rendered below the description
dismissiblebooleanfalseShows a close button in the top-right corner
onDismiss() => void—Called after the collapse animation finishes and the component unmounts
openboolean—Controlled open state; managed internally when omitted (uncontrolled)
defaultOpenbooleantrueInitial open state in uncontrolled mode
onOpenChange(open: boolean) => void—Called when the open state changes (with false when the close button is pressed)
livebooleanfalseWhen title/description content changes while open, the icon pops once
titleAs"h3" | "h4" | "h5" | "div""h5"Element used for the title (not forced to be a heading)
durationnumber150Duration of the fade-up entrance (ms)
collapseDurationnumber180Duration of the height collapse on dismiss (ms)
dismissLabelstring"關閉提示" (Dismiss alert)Accessible label for the close button; the English registry version defaults to "Dismiss alert"
classNamestring—Passed to the outermost container (put margins here; they collapse on dismiss too)

How it works

  • Default icons (lucide): Info for default and info, CircleCheck for success, TriangleAlert for warning, CircleX for destructive.
  • Override the band colour with the CSS variable --wb-alert-callout-accent (e.g. className="[--wb-alert-callout-accent:#7c3aed]"); when unset, it follows the variant palette.
  • The root element writes --wb-alert-callout-duration and --wb-alert-callout-collapse-duration; the close button's hover colour transition uses the former.
  • Collapse animation: opacity fades out during the first third while height, marginTop and marginBottom collapse to 0 with easeInOut. When stacking callouts, space them with each callout's own className="mb-3" rather than a parent gap, so the spacing collapses too instead of jumping on unmount.
  • overflow: hidden is only enabled during the collapse, so the close button's focus ring and any shadow you add are never clipped otherwise.
  • live compares the rendered text of the title and description, so passing new JSX with unchanged text does not trigger a pop.

Accessibility

  • destructive and warning use role="alert" (announced immediately); other variants use role="status"; title and description are linked via aria-labelledby / aria-describedby
  • The title renders as h5 by default; use titleAs to match your page's heading level or fall back to a div
  • The close button is type="button" with an aria-label and a visible focus-visible ring
  • On dismiss, if focus is inside the callout it moves to the next callout's close button, otherwise the previous one, otherwise the parent container, so focus is never lost; the exiting callout is inert, so it cannot be clicked or tabbed to
  • When the user has reduce motion enabled, the entrance is a plain fade (no movement), dismissing fades out in 100ms without collapsing, and live does not pop