Alert
An inline status message rendered as a bordered, tinted panel, colored by one of five semantic tones and announced to assistive technology through role="alert" plus a configurable aria-live politeness.
We could not charge your card
Visa ending 4242 was declined on 14 September. Invoices stay open for seven days before the workspace drops to the free plan.
You are at 92% of your build minutes
Builds keep running past the limit and bill at $0.008 per minute.
Domain verified
acme.com now serves your workspace over HTTPS.
View code
let dismissed = false;
function toggleDismissed() {
dismissed = !dismissed;
void handle.update();
}
<div mix={[vstack({ gap: 3, align: "stretch" }), is("100%"), maxIs("34rem")]}>
<Alert color="danger" live="assertive">
<Alert.Icon>
<CircleAlertIcon />
</Alert.Icon>
<Alert.Content>
<Alert.Title>We could not charge your card</Alert.Title>
<Alert.Description>
Visa ending 4242 was declined on 14 September. Invoices stay open for seven days
before the workspace drops to the free plan.
</Alert.Description>
</Alert.Content>
<Alert.Action>
<Button type="button" color="danger" size="sm">
Update card
</Button>
</Alert.Action>
</Alert>
{dismissed ? (
<Button
type="button"
variant="outline"
color="neutral"
size="sm"
mix={[self("start"), on<HTMLButtonElement, "click">("click", toggleDismissed)]}
>
Show the dismissible alert
</Button>
) : (
<Alert
id="preview-alert-quota"
color="warning"
// A page is read at its own pace, so the countdown stays off and dismissal
// comes only from the button. A queued notice passes a duration instead.
mix={[
dismiss({ duration: null }),
on<HTMLDivElement, "ui:dismiss">("ui:dismiss", toggleDismissed),
]}
>
<Alert.Icon>
<TriangleAlertIcon />
</Alert.Icon>
<Alert.Content>
<Alert.Title>You are at 92% of your build minutes</Alert.Title>
<Alert.Description>
Builds keep running past the limit and bill at $0.008 per minute.
</Alert.Description>
</Alert.Content>
<Alert.Action>
<Button
type="button"
variant="ghost"
color="warning"
size="sm"
commandfor="preview-alert-quota"
command="--ui-dismiss"
>
Dismiss
</Button>
</Alert.Action>
</Alert>
)}
<Alert color="success">
<Alert.Icon>
<CircleCheckIcon />
</Alert.Icon>
<Alert.Content>
<Alert.Title>Domain verified</Alert.Title>
<Alert.Description>acme.com now serves your workspace over HTTPS.</Alert.Description>
</Alert.Content>
</Alert>
</div>Installation
An ordinary dependency: install it, import the theme once, and import the component where it is used.
npm add @sdxc/uiimport "@sdxc/ui/theme.css";Usage
import { Alert } from "@sdxc/ui";Renders an inline status panel tinted by Alert.Props.color, gaining
inline-start padding through :has() when a direct Alert.Icon
needs the room. role, aria-atomic, and aria-live stay overridable.
Composition
The parts the component publishes, each a static property of the host.
AlertAlert.IconRenders Alert.IconProps.children as the alert's leading icon, absolutely positioned at the panel's inline/block-start corner with any direct SVG sized to1rem.Alert.ContentRenders Alert.ContentProps.children as the alert's body block: a column flex container that shrinks to fit alongside a leading icon or trailing action, holding Alert.Title and Alert.Description.Alert.TitleRenders Alert.TitleProps.children as the alert's heading, inside the native heading element matching the nearest ancestorHeadingScope's depth — or<h1>where no scope wraps it — styled as a small, tight label.Alert.DescriptionRenders Alert.DescriptionProps.children as the alert's supporting message, slightly translucent against the alert's foreground color so it reads as secondary to the title.Alert.ActionRenders Alert.ActionProps.children as the alert's trailing control — a button, link, or dismiss affordance — pinned to the panel's block-start edge at its own natural size.
Examples
<Alert color="success" live="assertive">
<Alert.Content>
<Alert.Title>{t("alerts.saved.title")}</Alert.Title>
</Alert.Content>
</Alert>Props
Read from the component's own types, so every prop, every default and every allowed value is listed.
| Prop | Type | Description |
|---|---|---|
color? | "brand" | "neutral" | "success" | "warning" | "danger" | Semantic tone of the alert. Default: "neutral". |
live? | "polite" | "assertive" | "off" | aria-live politeness for dynamic alerts. Default: "polite". |
children | RemixNode | The alert's compound parts: Alert.Icon, Alert.Content, Alert.Action, or any other content. |
Also accepts everything in TagProps<"div">.
Alert.Icon
| Prop | Type | Description |
|---|---|---|
children | RemixNode | The icon graphic, typically a single SVG icon. |
Also accepts everything in TagProps<"div">.
Alert.Content
| Prop | Type | Description |
|---|---|---|
children | RemixNode | The alert's title, description, or other body content. |
Also accepts everything in TagProps<"div">.
Alert.Title
| Prop | Type | Description |
|---|---|---|
children | RemixNode | The alert's heading text. |
Also accepts everything in TagProps<"h1">.
Alert.Description
| Prop | Type | Description |
|---|---|---|
children | RemixNode | The alert's supporting message text. |
Also accepts everything in TagProps<"p">.
Alert.Action
| Prop | Type | Description |
|---|---|---|
children | RemixNode | A button, link, or other control the alert offers, e.g. "Retry" or "Dismiss". |
Also accepts everything in TagProps<"div">.
Types
| Name | Values | What it decides |
|---|---|---|
Color | "brand" | "neutral" | "success" | "warning" | "danger" | Semantic tone driving the host element's border, tint, and foreground color through the --ui-* variables for that color. |
Live | "polite" | "assertive" | "off" | aria-live politeness applied to the host element. |