Alert
betav0.1.0Inline feedback banner: an elevation surface with a severity-coloured left rule, a severity glyph, the message and an optional trailing action slot. It replaces `@mui/material` `Alert` and `AlertTitle`, which the products render at 286 sites across 193 files (OpenCTI 196, OpenAEV 90; plus 40 `AlertTitle` sites), measured on each product's `design-system/current` on 2026-09-18. Alert stays in the document flow and is read by the page around it; the transient counterpart that floats over the page and can be dismissed is `Snackbar`. THE SURFACE RULE — an Alert paints an elevation surface, so it is only legible on a DIFFERENT layer from the surface behind it. On a default-gradient, layer-0 or layer-1 host it takes elevation 2, which is the default; on a layer-2 host it takes elevation 1, the one case that passes a value. Getting it wrong does not throw — it paints the Alert the same colour as its own background. IN LIGHT MODE the rule does not apply and there is nothing to pass: the light elevation ramp cannot separate the banner from the page (layer-2 against layer-0 measures 1.02:1), so in light the Alert paints a 20 % severity wash and separates by hue instead. Dark is unchanged. `severity` is required on purpose: the severity is the message's meaning, and MUI's `success` default is how a mislabelled banner ships unnoticed. The message goes in `title` — a one-line Alert is a title, never a lone description — and an optional second line in `description`.
Variants
the surface rule — which layer the Alert takes on each host
host: default gradient → elevation 2 (the default). In light: severity wash.
Indicators are refreshed every 15 minutes.
host: layer 0 → elevation 2 (the default). In light: severity wash.
Report saved.
host: layer 1 → elevation 2 (the default). In light: severity wash.
This feature needs an active licence.
host: layer 2 → elevation 1, the one case that passes a value (dark only)
Three observables could not be parsed.
same layer-2 host, DEFAULT elevation — dissolves in DARK; in light the wash still separates it
Three observables could not be parsed.
every severity — title, description and an action
Title (error)
Description
Title (info)
Description
Title (success)
Description
Title (warning)
Description
Title (ia)
Description
one line — the title stays a title, and everything centres on the glyph
A error message, on one line.
A info message, on one line.
A success message, on one line.
A warning message, on one line.
A ia message, on one line.
no action, wrapping description
Retention policy
Objects older than the retention window are removed from the platform every night, and this operation cannot be undone once the nightly job has started.
Examples
<Alert severity="info" title="Indicators are refreshed every 15 minutes." /><Alert
severity="error"
title="Import failed"
description="Three observables could not be parsed."
/>// THE SURFACE RULE — the only host that passes a value is a layer-2 one.
<Paper elevation={2}>
<Alert severity="warning" title="This feature needs an active licence." elevation={1} />
</Paper><Alert
severity="warning"
title="Enterprise Edition"
description="This feature needs an active licence."
action={<Button priority="secondary" size="sm">Learn more</Button>}
/><Alert severity="ia" title="Generated by the assistant — review before sharing." />// Migrating from MUI: the body becomes the TITLE, and an AlertTitle child
// becomes the title with the body moving down to description.
// <Alert severity="error"><AlertTitle>Import failed</AlertTitle>Body</Alert>
<Alert severity="error" title="Import failed" description="Body" />Props
| Prop | Type |
|---|---|
severity | "error" | "info" | "success" | "warning" | "ia" — REQUIRED. Selects the left rule, the glyph and the default live-region role. Deliberately has no default: a wrong severity is a wrong message. |
title | ReactNode — REQUIRED. The message, and the primary line. A one-line Alert is a title, never a lone description. |
description | ReactNode — optional second line, below the title. |
action | ReactNode — trailing control slot (Figma `actionButton`). Rendered only when provided. Pass a `Button` with `priority="secondary" size="sm"` to match the frame. |
elevation | 0 | 1 | 2 | 3 (PaperElevation) — which elevation layer the Alert's own surface paints. Defaults to 2. THE SURFACE RULE: default gradient, layer-0 and layer-1 hosts all take the default 2; a layer-2 host is the one case that passes a value, and it passes 1. Same prop name, type and layer-N mapping as Paper and Card. |
role | "alert" | "status" — overrides the default live-region role, which is "alert" for error and warning and "status" for info, success and ia. |
className | string — merged onto the root through `cn()`. |
Accessibility
Ratios are the computed output of pnpm check:contrast, on all three surfaces the pairs above declare. REGIME, stated because a green gate only covers what was declared to it: the Alert always carries a `layer-N` class of its own, so `--bg-elevation-default` — which resolves at :root, i.e. layer 0 — is the one surface it NEVER paints. It is declared because check:contrast Rule 5 derives its requirement from the `bg-elevation-default` class; the surfaces that describe what is really drawn are layer 2 (the default) and layer 1 (the layer-2-host case). Worst case across all three surfaces and both modes: title (--text-alert) 14.28:1, description (--text-default-secondary) 7.38:1, both against a 4.5 floor; glyphs and rules 4.26:1 at worst against a 3 floor (error on layer 2, dark). Every pair clears its threshold on every declared surface in both modes. 1.4.1: severity is never carried by colour alone — each severity has its own glyph shape (circle-x, info, circle-check, triangle-alert, the IA mark) and the message states the condition. 1.1.1: the glyph is decorative, aria-hidden on its wrapper, because the message already carries the meaning. 4.1.2 / 4.1.3: the root is a live region — role="alert" (assertive) for error and warning, role="status" (polite) for info, success and ia, overridable through `role`. A live region only announces content that arrives after it is in the DOM; an Alert rendered with the page is read in document order instead, which is the intended behaviour for an inline banner. 2.1.1 / 2.4.7: the root is not focusable and has no keyboard interaction of its own. The only focusable element is whatever the host passes in `action`, which brings its own focus ring (Button, IconButton) — so this component deliberately declares none: there is nothing of its own to focus. The component has no disabled state, so no WCAG 1.4.3 Note 1 exemption is claimed.