Skip to main content

Alert

betav0.1.0

Inline 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.

host: layer 2 → elevation 1, the one case that passes a value (dark only)

same layer-2 host, DEFAULT elevation — dissolves in DARK; in light the wash still separates it

every severity — title, description and an action

Title (info)

Description

Title (success)

Description

Title (ia)

Description

one line — the title stays a title, and everything centres on the glyph

A info message, on one line.

A success message, on one line.

A ia message, on one line.

no action, wrapping description

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

PropType
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.
titleReactNode — REQUIRED. The message, and the primary line. A one-line Alert is a title, never a lone description.
descriptionReactNode — optional second line, below the title.
actionReactNode — trailing control slot (Figma `actionButton`). Rendered only when provided. Pass a `Button` with `priority="secondary" size="sm"` to match the frame.
elevation0 | 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.
classNamestring — merged onto the root through `cn()`.

Accessibility

2.1 AAWCAG pass

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.