Alert

Tells the person about something on this page and what to do next.

Examples

A note

Traces are sampled at 10%

Raise it to keep every span.

Dismissible

Traces now last 30 days.

Failed, with a retry

Sync failed

The help center returned 503.

Status

  • Approvals are off

    Tools run without asking.

    neutraldefault

  • Reply limit at 82%

    New tickets queue at the limit.

    warn

  • Sync failed

    The help center returned 503.

    fail

Placement

  • Key expires in 3 days

    Rotate it before Friday.

    inlinedefault

  • Replies at 92%. New tickets queue soon.

    page

Sizes

  • Traces are sampled

    One span in ten is kept.

    defaultdefault

  • Read only. Ask an owner to edit this grid.

    sm

States

  • Approvals are off.

    rest

  • Approvals are off.

    close hover

  • Approvals are off.

    close focus

  • Approvals are off.

    close pressed

  • Sync failed.

    action pending

Usage

When to use it
Use
Something about the current view needs reading before the person acts: a limit is near, a setting is off, a sync failed.
Use
The state lasts as long as its cause, so the message stays until the cause is fixed.
Use
A whole page or the app shell is affected: use placement="page" across its top.
Not for
Confirming an action the person just took. Use Toast.
Not for
A region failed to load and has nothing else to show. Use Empty state.
Not for
A field has invalid input. Use Field.
Not for
The person must decide before anything else can happen. Use Dialog.

Rules

12 rules
Never
Render AlertClose on status warn or fail; remove the alert only when the cause is gone. Because a dismissed failure hides a problem that still exists, so AlertClose renders nothing on those statuses.
Must
Pass a dismissKey that carries a version of the message when a neutral alert can be dismissed. Because the dismissal is stored under the key, so a fixed key also hides the changed message that follows.
Must
Show one placement="page" alert at a time; merge the second or move it inline next to its cause. Because stacked page strips push the content down and leave no single thing to read first.
Must
Give an alert one AlertAction with a size="sm" Button; put other paths in the description as links. Because two buttons in the action slot wrap under the message on a narrow alert and split the next step.
Should
Name what happened in the title, under 48 characters, never the status.
Should
Lead a short alert with <strong> ending in a period inside AlertDescription, not an AlertTitle.
Should
Say what happens next or what to do, with numbers, in one or two sentences.
Must
Pass announce={false} on an alert that is part of the page from first render. Because the default role="status" or role="alert" makes a screen reader read a standing note as news.
Must
Keep the status icon on warn and fail, or name the status in the title. Because the icon is the only other status cue, and a color-only cue vanishes in forced colors and for color-blind readers.
Never
Use an Alert for success; there is no success status. Use a toast. Because a success alert stays on the page after the work is done, and green is not a Quartz status hue.
Never
Add a border or left stripe to an Alert. Because the alert already draws one frame line, and the icon and title carry the status; a stripe hue drifts from the status tokens.
Must
Mark warn and fail with status, which sets the icon; never fill the alert with the wash. Because a tinted block reads as a Bootstrap alert and buries the words under the colour; trouble is marked where it is.

Accessibility

6 checks
Warn and fail render role="alert"; other statuses render role="status".
Static notes pass announce={false} so nothing is read on load.
AlertClose is a type="button" with aria-label "Dismiss".
The status icon is aria-hidden; the icon shape and the title carry the status in forced colors.
The alert takes no focus; Tab reaches AlertAction, then AlertClose.
Dismissing moves focus to the next focusable element.

Edge cases

12 edge cases
Long title and description
Wraps at word boundaries; an ID breaks inside the box.
No children
Renders nothing, no icon and no box.
Under 12rem wide
Close joins the icon row; text runs full width; the action wraps under.
Right to left
Icon, text and action mirror through flex order.
Zoom 200%
Text wraps word by word; the action drops under it; nothing clips.
Inside a card
Render it as the card's first row rather than a frame in a frame.
Retry fails again
Update the description and keep the alert; never swap to a toast.
Slow action
The Button keeps its box and label while pending.
Close pressed ten times
The first dismisses and unmounts; the rest land on nothing.
Inside a form
AlertClose is type="button" and never submits.
Forced colors
Fills drop; icon shape and words tell the statuses apart.
Touch
AlertClose is 28px with a 36px hit area; hover is guarded.

API

8 props
status
'neutral' | 'warn' | 'fail' default 'neutral'
placement
'inline' | 'page' default 'inline'
size
'default' | 'sm' default 'default'
inset
boolean default false
icon
boolean | ReactNode default true inline
announce
boolean default true
dismissKey
string
onDismiss
() => void

Tokens

21 tokens
--surface-page
var(--paper)
--line-frame
oklch(var(--ink-c) / var(--line-frame-alpha))
--accent-mark
var(--ink)
--warn-mark
oklch(80% 0.152 68)
--fail-mark
oklch(65.2% 0.219 26)
--warn-text
oklch(49% 0.100 68)
--fail-text
oklch(51% 0.180 26)
--radius-soft
6px
--radius-frame
10px
--control
32px
--space-3
12px
--space-4
16px
--type-label
400 14px/16px var(--font-sans)
--type-body-sm
380 13px/18px var(--font-sans)
--text-1
var(--ink)
--text-2
oklch(var(--ink-c) / 0.80)
--button-ghost-hover
oklch(var(--ink-c) / 0.05)
--surface-pressed
oklch(var(--ink-c) / 0.08)
--border-focus
var(--ink)
--line-focus
2px
--dur-fast
120ms

Install

For your coding agent

GitHub

Please star me pookie

141

A new design system every week

Leave your email before you copy the prompt.