Spec version v0.2.0

Alert

Purpose

An Alert is an inline message banner that communicates a non-blocking status, warning, or informational message directly within the page content. Use an Alert to inform the user about the state of a process, a validation outcome, or a system condition that is relevant to the current context — for example, a warning that a feature is deprecated, confirmation that a form was saved, an error that prevented an action from completing, or a tip about the current workflow. Do NOT use an Alert for urgent interruptions that require immediate user acknowledgment before proceeding — use a Dialog for those. Do NOT use an Alert for brief transient feedback like "Saved successfully" that disappears after a few seconds — use a Toast for that.

Alerts are page-flow elements. They render in the DOM at their natural position within the content layout, not as floating overlays.

Anatomy

An Alert is a horizontal container composed of up to four parts:

  • Container (required): the outer element that establishes the left-border accent, background tint, and text color for the chosen variant. The container uses role="alert" so assistive technologies announce new alert content automatically.
  • Status icon (optional): a variant-matched status icon placed to the left of the alert text. Use Material Symbols Rounded icons: check_circle for success, warning for warning, error for error, info for info, and the brand indigo circle for primary. The icon is 16px, vertically aligned to the first line of the title. It inherits the variant's text color token. Do NOT use an icon that contradicts the variant color — a red icon in an info (blue) alert creates a conflicting signal.
  • Content column (required): a vertical stack containing the title and description. Sits to the right of the icon (or at the left edge if no icon is present).
    • Alert title (optional but strongly recommended): a short, scannable headline for the message. --force-font-size-sm (14px), --force-font-weight-medium (500). A title alone with no description is valid for brief alerts.
    • Alert description (optional): the detailed message body. --force-font-size-sm (14px), --force-font-weight-regular (400), --force-color-text-secondary relative to the variant. Inline links inside the description use --force-color-text-link. Long descriptions should be kept to two to three sentences — if more explanation is needed, link to documentation.
  • Dismiss button (optional): an icon button (X icon) in the top-right corner of the alert container. Use only for alerts that are advisory and non-critical. Do NOT include a dismiss button on error alerts that describe a blocking problem — the problem must be resolved, not dismissed. The dismiss button is a standard tertiary icon button and follows Button accessibility rules.

Variants

All alert variants use the left-border accent pattern: a 4px solid left border in the variant's border token, a subtle tinted background, and variant-matched text color. This is the consistent visual grammar for alerts across the Force UI system. Do NOT use a top border, a bottom border, or a full border as the accent — the left border is the canonical pattern.

success

Use when an action has completed successfully or a system condition is healthy. Background: --force-color-bg-success-subtle. Left border: 4px solid var(--force-color-border-success). Text: --force-color-text-success. Icon: check_circle in --force-color-icon-success. Use success alerts for confirmations after a user-initiated process completes (e.g., "Repository cloned successfully") or for persistent health indicators (e.g., "All checks passed").

warning

Use when a condition requires user attention but does not prevent current operation. Background: --force-color-bg-warning-subtle. Left border: 4px solid var(--force-color-border-warning). Text: --force-color-text-warning. Icon: warning in --force-color-icon-warning. Use warning alerts for deprecation notices, impending expirations, configuration recommendations, and degraded-but-functional states.

error

Use when an operation has failed, a blocking condition exists, or invalid input has been detected at the form or section level. Background: --force-color-bg-error-subtle. Left border: 4px solid var(--force-color-border-error). Text: --force-color-text-error. Icon: error in --force-color-icon-error. Error alerts must describe the problem clearly and, where possible, tell the user what action resolves it. Do NOT use an error alert to log technical error codes without a human-readable explanation.

info

Use for neutral informational messages with no urgency — guidance, tips, notices, and non-critical system information. Background: --force-color-bg-info-subtle. Left border: 4px solid var(--force-color-border-info). Text: --force-color-text-info. Icon: info in --force-color-icon-info. Info is the correct variant for "What does this setting do?" explanations placed inline within forms, and for feature flags or beta notices.

primary (brand)

Use for brand-aligned announcements, onboarding callouts, or feature introductions that are positive in nature but not categorically a "success" event. Background: --force-color-bg-primary-subtle. Left border: 4px solid var(--force-color-border-primary). Text: --force-color-text-primary-brand. Icon: the brand icon or a star/sparkle for feature introductions. Use this variant sparingly — it carries brand indigo and should not appear alongside multiple other primary-brand-colored elements on the same page.

States

Default: The alert is visible and stationary. Content is fully rendered. This is the only visual state for non-dismissible alerts.

Dismissed (animating out): When the user activates the dismiss button, the alert animates out before being removed from the DOM. Use opacity: 0 + a slight upward translate, with transition-duration: --force-duration-normal (250ms) and --force-easing-accelerate. After the animation completes, remove the element from the DOM entirely. Do NOT use display: none alone — the layout shift without animation is disorienting.

Dismiss button — hover: The dismiss icon button transitions to --force-color-bg-interactive-hover background. Duration --force-duration-fast (150ms).

Dismiss button — focus: The dismiss button receives --force-shadow-focus-ring + --force-color-border-focus. Focus applies to the button element only, not the alert container.

Loading / pending state (rare): When an alert describes an in-progress operation (e.g., "Deployment in progress…"), the title may optionally include a Spinner component to the left of the title text. This is informational — the spinner does not represent a blocking interaction.

Behavior

Alerts are static, non-interactive containers. They do not respond to hover on the container itself. The only interactive elements inside an alert are inline links within the description and the optional dismiss button.

Alerts appear at their natural position in the document flow. They do not float, they do not use position: fixed, and they do not appear above other content. When an alert is injected into the page dynamically (e.g., after a form submission fails), it should appear at the top of the relevant form or section, not in a remote area of the page. Proximity to the context that triggered the message is essential for usability.

Multiple alerts may appear stacked on a page if multiple independent conditions exist simultaneously. Stack them with --force-spacing-3 (12px) gap. Do NOT display more than three alerts on a single view without a mechanism to collapse or dismiss them — multiple simultaneous alerts indicate a design problem, not a normal state.

Do not auto-dismiss alerts unless the content is genuinely transient (use Toast for transient feedback). Persistent alerts remain visible until the user dismisses them or the underlying condition resolves.

Accessibility

The alert container uses role="alert" (or the equivalent aria-live="assertive" region). This causes screen readers to announce the alert content immediately when it is injected into the DOM. Use this power responsibly — do not render alerts on page load for content that is not time-sensitive, as it will interrupt the screen reader's announcement queue.

For alerts that describe a non-urgent condition present at page load (e.g., a persistent warning that a license is expiring), use role="status" with aria-live="polite" instead of role="alert". This allows the screen reader to announce the content after the user stops interacting with other elements, rather than interrupting.

The dismiss button requires an aria-label that identifies the alert it dismisses. Use aria-label="Dismiss {alert title}" (e.g., aria-label="Dismiss: Deployment warning"). A generic aria-label="Close" or aria-label="Dismiss" is not acceptable when multiple alerts appear on the same page, as screen reader users cannot distinguish between them.

Do not rely on the left-border color or icon alone to convey variant. The alert title must include sufficient context (e.g., "Warning: your license expires in 7 days") so that users who cannot perceive color still receive the status information from the text.

Inline links inside alert descriptions must have descriptive link text. Do NOT use "click here" or "learn more" as link text — use the target name (e.g., "View upgrade options" or "See the migration guide").

Composition

Alerts appear most commonly:

  • At the top of a form section: below the section heading, above the first form field. Use for section-level validation summaries or precondition warnings.
  • At the top of a tab content area: directly below the tab panel's top edge. Use for persistent tab-level notices (e.g., a deprecation warning for the entire settings section).
  • Inside a Card's content area: as the first element in CardContent. Use for entity-level status messages (e.g., "This repository is archived and read-only").
  • At the top of a modal: inside the modal content area, below the modal title. Use for modal-level confirmations or errors.
  • Below a form field (field-level errors): field-level validation errors belong inside the Field component as helper text using --force-color-text-error, not as an Alert component. Use Alert only for section-level or page-level error conditions.

Do not place an Alert inside another Alert. Do not nest an Alert inside a Toast or a Dialog footer. Do not use an Alert as a replacement for form field validation — field errors belong at the field level (see the Field and Input pattern files).

Guidance

Choose the variant that matches the actual semantic meaning of the message, not the color that fits the surrounding design. An info-variant alert on a page that already uses indigo brand elements does not clash — the semantic color palette is designed to coexist.

Do NOT use an Alert for decorative callouts. If a piece of information is not a status, a warning, an error, or a brand-specific announcement, it does not belong in an Alert. Use a prose block, a descriptive Card content area, or a styled typography element instead.

Do NOT dismiss error alerts that describe an unresolved blocking condition. Error alerts that say "Connection failed" or "Access denied" must remain visible until the condition is resolved. Giving the user a dismiss button on a blocking error creates a false sense that the problem has been handled.

Prefer brevity in alert titles. The title is the first and often only thing a user reads. "Warning" alone is not a useful title — say what is warned. "Your API token expires in 3 days" is a title. "Token expiry warning" is not.

Avoid stacking semantic alerts of the same variant. Two warning alerts on the same page surface compound attention, creating noise rather than urgency. If two warning conditions exist simultaneously, evaluate whether they can be consolidated into one alert with a list of items.

Token Usage

Container (all variants)

  • Left border: 4px solid var(--force-color-border-{variant}) — tokens: --force-color-border-success, --force-color-border-warning, --force-color-border-error, --force-color-border-info, --force-color-border-primary
  • Background: --force-color-bg-{variant}-subtle — tokens: --force-color-bg-success-subtle, --force-color-bg-warning-subtle, --force-color-bg-error-subtle, --force-color-bg-info-subtle, --force-color-bg-primary-subtle
  • Border radius: --force-radius-lg (8px) on the three non-left corners (or full radius with left override)
  • Padding: --force-spacing-4 (16px) vertical, --force-spacing-4 (16px) horizontal (adjust by context)

Text

  • Alert title: --force-font-size-sm (14px), --force-font-weight-medium, respective variant text token
    • --force-color-text-success, --force-color-text-warning, --force-color-text-error, --force-color-text-info, --force-color-text-primary-brand
  • Alert description: --force-font-size-sm (14px), --force-font-weight-regular, --force-color-text-secondary
  • Inline links inside description: --force-color-text-link

Icon

  • Size: 16px (--force-font-size-base height equivalent)
  • Color: --force-color-icon-success, --force-color-icon-warning, --force-color-icon-error, --force-color-icon-info
  • Vertical alignment: aligned to first line of title text
  • Gap to content column: --force-spacing-3 (12px)

Dismiss button

  • Uses tertiary icon button styles
  • Hover background: --force-color-bg-interactive-hover
  • Focus ring: --force-shadow-focus-ring + --force-color-border-focus

Motion (dismiss animation)

  • Exit: opacity: 0 + translateY(-4px), --force-duration-normal (250ms), --force-easing-accelerate
  • Color/border transitions on render-in: --force-duration-fast (150ms), --force-easing-standard