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.enPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<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.jsonOr, 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
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "default" | "info" | "success" | "warning" | "destructive" | "default" | Semantic variant; controls the leading icon, accent band and colours |
title | ReactNode | — | Title text |
description | ReactNode | — | Description content |
icon | ReactNode | null | per variant | Overrides the default icon; pass null to hide it |
action | ReactNode | — | Action slot (e.g. a "Refresh" button), rendered below the description |
dismissible | boolean | false | Shows a close button in the top-right corner |
onDismiss | () => void | — | Called after the collapse animation finishes and the component unmounts |
open | boolean | — | Controlled open state; managed internally when omitted (uncontrolled) |
defaultOpen | boolean | true | Initial open state in uncontrolled mode |
onOpenChange | (open: boolean) => void | — | Called when the open state changes (with false when the close button is pressed) |
live | boolean | false | When 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) |
duration | number | 150 | Duration of the fade-up entrance (ms) |
collapseDuration | number | 180 | Duration of the height collapse on dismiss (ms) |
dismissLabel | string | "關閉提示" (Dismiss alert) | Accessible label for the close button; the English registry version defaults to "Dismiss alert" |
className | string | — | Passed to the outermost container (put margins here; they collapse on dismiss too) |
How it works
- Default icons (lucide):
Infofor default and info,CircleCheckfor success,TriangleAlertfor warning,CircleXfor 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 thevariantpalette. - The root element writes
--wb-alert-callout-durationand--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 parentgap, so the spacing collapses too instead of jumping on unmount. overflow: hiddenis only enabled during the collapse, so the close button's focus ring and any shadow you add are never clipped otherwise.livecompares 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 userole="status"; title and description are linked viaaria-labelledby/aria-describedby - The title renders as
h5by default; usetitleAsto match your page's heading level or fall back to adiv - The close button is
type="button"with anaria-labeland 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
livedoes not pop
Logo Trace Loader
A React loader where a short dash orbits a logo's outline; on completion it closes into a full stroke and fades in the fill. Defaults to the WebberUI brand curve, accepts any path and can run as a full-page overlay.
Progress Bar
A spring-tweened linear progress bar with a rolling percentage, an indeterminate sweep and buffer layer, and a single pulse with a check mark on reaching 100%.