Components / feedback

Alert

The close is its own part, and its own decision. data-part="close" is a button with one job, appearing only when onDismiss is passed; action is the slot that may hold an undo. Two controls, two names, and either can be left off.

Rendered from the package · open on its own

Summary

A message the reader must see, announced without stealing focus.

APG patternAlert
Built onnative elements
Statusstable
Since0.1.0
<Alert intent="negative" icon={<Icon path={ICONS.warningCircle} size="md" />} title="Publishing failed">
  The domain maya.studio is not verified yet. Point a CNAME at studioedit.app and try again.
</Alert>

Anatomy

A <div data-se="alert"> carrying role="alert" or role="status".

PartElementRequired
action<span>no
close<button>no
content<div>yes
icon<span>no
title<span>no

Properties

PropertyValuesDefaultWhat it does
intentaccent · positive · negative · warning · neutralaccentWhat kind of message this is. It sets the color and the icon slot's tint, and never stands alone — the words carry the meaning.
liveassertive · politeassertiveassertive interrupts the reader; polite waits its turn. Default assertive.
iconReact.ReactNodenoneAn <Icon>. Required in practice — color must never carry the meaning alone.
titlestringnoneA short heading above the message. Omit it when the message is one sentence; two lines of heading and body saying the same thing is one too many.
actionReact.ReactNodenoneA dismiss or undo control, pinned to the trailing edge. Omit it and there is none.
onDismiss() => voidnoneAdds a close button. It is a signal, not a removal: clear the Alert's content and leave it mounted, because unmounting takes the live region with it and the next message is never announced. Omit this and there is no close button.
dismissLabelstringDismissThe close button's accessible name. Its visible content is a glyph.

States

StateExpressed as
Focused:focus-visible
Hover:hover

Behavior

It announces when its text changes. It never moves focus — that is the difference between an alert and an AlertDialog.

Accessibility

The element must already be in the DOM before the text changes, or a screen reader announces nothing. Render an empty Alert and fill it; do not mount the component when the message arrives. This is the single most common way live regions silently fail.

assertive interrupts whatever is being read and is the default. Use it when the reader cannot continue without knowing. polite waits for a pause and is right for confirmations.

Never color alone. Always pass an icon and say the problem in words — a red border is a second signal, never the only one.

Keyboard

None of its own. It is not focusable and takes no keys.

Roles, states and properties

AttributeSet by
aria-hiddenalways true
aria-labelset at render
aria-liveset at render
rolealways alert, always status, set at render

Focus

It never takes focus, and that is the point. An alert announces without interrupting what the reader is doing. Something that must be dealt with before continuing is an AlertDialog.

Screen reader

Not recorded as verified. Stage 4 of the readiness ladder — driving each component with VoiceOver and NVDA — is unstarted across the package, and no component should claim otherwise until docs/journal/ records the session that did it.

Contrast and target size

npm run check:contrast audits every color pair this component uses across all four skins, light and dark, and fails the build on a shortfall. Two waivers are on the record in docs/audit/DEFERRED.md.

It sets no target size of its own; anything interactive inside it brings its own.

Tested

  • test/browser/icon-box.spec.mjs

Known gaps

_No upstream requirement is recorded as not applicable._

Appearance

TokenUsed for
--se-accentintent
--se-bgbackground, border
--se-border-widthborder
--se-focus-coloroutline
--se-focus-offsetoutline-offset
--se-focus-widthoutline
--se-icon-mdblock-size, font-size, inline-size
--se-icon-smblock-size, font-size, inline-size
--se-leading-leadline-height
--se-leading-uiline-height
--se-mix-lineborder
--se-mix-softbackground
--se-negativeintent
--se-positiveintent
--se-radius-mdborder-radius
--se-radius-smborder-radius
--se-space-1gap
--se-space-3gap, padding
--se-space-4padding
--se-surface-sunkbackground
--se-textcolor, intent
--se-text-mdfont-size
--se-text-mutedcolor
--se-text-smfont-size
--se-warningintent
--se-weight-mediumfont-weight

Motion

None. A message that animates in while a screen reader is already reading it is two things happening at once.

Content

Errors say what happened and how to fix it. The domain is not verified. Point a CNAME at studioedit.app — not Something went wrong.

Name the thing that failed. A reader with three drafts open needs to know which one.

No apology. The message is the fix, not the feeling.

Usage

Page level, section level and field level are three different placements and a message belongs at the narrowest one that can hold it. A field's own error goes in Field; a section's goes in an inline Alert; only something that invalidates the whole page goes above it.

When not to use it. For a confirmation that can be missed — that is a Toast. For something the reader must answer before continuing — that is an AlertDialog, which does take focus.

Notes

action fills data-part="action", and the part was widened to match the prop rather than the prop narrowed to match the part — the type documents it as "a dismiss or undo control", and dismiss named one of the two. This page said the opposite until 0.2, describing a defect that had already been fixed.

The close is its own part, and its own decision. data-part="close" is a button with one job, appearing only when onDismiss is passed; action is the slot that may hold an undo. Two controls, two names, and either can be left off.