Alert
An inline status message — a tinted box with a status tile, a title, body text and an optional button.
alert-messageOpen in Figma ↗A static, prominent page-level message that communicates the status or outcome of an action, setting, or app condition. It stays in the page/container flow and does not overlay the interface.
Use for: Status tied to nearby content or a whole section — account information, page updates, plan eligibility, applied settings, and action outcomes.
Not for: Transient confirmations or short-lived feedback — use snack-bar instead. Snack-bar is a temporary overlay; alert-message is static and part of the container.
Choosing: Use Stack=no for a single message. Use Stack=yes when two or more alerts apply to the same location at the same time — they share one slot, and the step-count indicator shows how many there are and which one is in view. Set State by meaning: Success for positive activity or change, Warning for caution or attention needed, Alert for a critical issue worth checking, Info for a neutral outcome, Info Midnight for a neutral message that needs more emphasis on a dark surface.
Rules: Place directly in the main page/container flow, adjacent to the content it refers to. Never place inside a section, card, or panel. Show a CTA only when a clear follow-up action is required — one per alert. Do not use Stack for a single message; keep the indicator dot count equal to the number of stacked alerts.
import SwiftUI import EandTokens // alert-message: padding 8, gap 12, r16 on the status-indicator tint. Mark = 32pt r12 // tile (padding 6) on the status colour with a 16pt white filled glyph. Title title/xs and // body body/md, both default ink. The action is a primary / sm / inverse button. struct AlertMessage: View { let title: String; let message: String var action: String? = nil var body: some View { HStack(alignment: .center, spacing: EandSpacing.md) { Image(systemName: "checkmark.circle.fill").font(.system(size: EandIcon.md)) .foregroundColor(EandColor.textDefaultInverse) .frame(width: EandScale.scale32, height: EandScale.scale32) .background(EandColor.statusPositive, in: RoundedRectangle(cornerRadius: EandRadius.radius4)) VStack(alignment: .leading, spacing: 0) { Text(title).font(.system(size: EandTypography.titleXs.size, weight: EandTypography.titleXs.weight)) Text(message).font(.system(size: EandTypography.bodyMd.size)) } .foregroundColor(EandColor.textDefaultDefault) Spacer(minLength: 0) if let action { InverseButton(title: action, size: .sm) {} } } .padding(EandSpacing.sm) .background(EandColor.statusIndicatorSurfacePositive) .clipShape(RoundedRectangle(cornerRadius: EandRadius.radius6)) } }
When to use
- Use for status that belongs to a place in the page and stays there: a plan about to expire, a payment that failed, a note about a service. One call to action per alert.
- Don't use for a passing confirmation (use Snackbar), for the outcome of a flow (use PageTitle or AlertModal), or for form validation (use the Input error state).
Choosing a status
status | Surface | Use for |
|---|---|---|
success | status-indicator/surface/positive | Something completed |
alert | status-indicator/surface/warning (amber) | Needs attention soon |
warning | status-indicator/surface/danger (orange) | A problem to resolve |
info (default) | status-indicator/surface/neutral | Neutral information |
info-midnight | alert-message/surface/midnight | Information on dark screens |
Figma's alert is the amber step and its warning the orange one. V1.2 has no red alert.
Anatomy
- Tile — a 32px tile in the status colour, holding a 16px white filled glyph.
- Text —
titleintitle/xsandchildreninbody/md. Both use the default ink on every status exceptinfo-midnight, which is white. - Action —
actionrenders a primarysminverse Button that callsonAction.actionPlacement="below"moves it under the text, for a body that runs to several lines. - Stack — when several alerts share one slot,
stack(the count) andstackIndex(the one in view, from 0) draw a vertical step counter beside the box.
<Alert status="alert" title="Your plan renews in 3 days" action="Review" onAction={review}>
AED 250 will be charged to your card.
</Alert>
<Alert status="info" stack={3} stackIndex={0}>Roaming is on for this trip.</Alert>Deprecated
tone is now status: positive becomes success, warning becomes alert, danger
becomes warning and default becomes info.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
action? | ReactNode | — | Label of the primary / sm / inverse button. One CTA per alert. |
actionPlacement? | 'end' | 'below' | end | Default end. Use below when the body runs to several lines. |
onAction? | (() => void) | — | |
stack? | number | — | Figma Stack=yes: how many alerts share this slot (2+ draws the step counter). |
stackIndex? | number | 0 | Which stacked alert is in view, 0-based. |
status? | 'alert' | 'success' | 'warning' | 'info' | 'info-midnight' | — | Figma State axis. Takes precedence over tone. |
title? | ReactNode | — | |
tone? | 'default' | 'warning' | 'positive' | 'danger' | — | Deprecated. Use status; warning maps to alert and danger to warning. |
Design
Figma source: alert-message — etisalat Consumer App DSL V1.2
- Box: padding 8 (
spacing/sm), gap 12 (spacing/md), 16px radius (border-radius/6). - Tile: 32px at a 12px radius (
border-radius/4), padding 6, onstatus/positive,status/warning,status/dangerorstatus/default;info-midnightusessurface/glass/white/md. - Text:
title/xsandbody/mdintext/default/default, ortext/default/inverseoninfo-midnight. The ink no longer follows the status. - Step counter: 5px dots on
midnight/400, 4px apart; the dot in view is 5 × 12 with a midnight head.