Snackbar
A transient midnight pill that confirms an action — a status tile, a message with an optional amount, and an optional button.
Snack-barOpen in Figma ↗A transient, non-blocking overlay that confirms a user action. It appears near the bottom of the viewport, above the current interface, without taking space in the page/container flow.
Use for: Immediate confirmation of a completed action or low-priority outcome — saved, copied, added, removed, settings updated, or an amount applied.
Not for: Persistent, critical, or detailed status, or messages that need a follow-up action — use alert-message instead.
Choosing: Use back-ground=no when the snack bar sits over a calm area of the screen. Use back-ground=yes when it overlays busy, scrolling, or dark content — it adds a blurred gradient scrim behind the pill to keep the message readable.
Rules: Keep copy to one clear outcome. Show one at a time; never stack snack bars. No CTA. Position above persistent bottom controls such as navbar or cta-bar and never overlap them. Never cause layout shift.
import SwiftUI import EandTokens // Snack-bar: midnight pill, r16, min 48 tall, padding 2/8/2/2, gap 10. The mark is a // 44pt r14 tile on the status tint holding a 24pt filled glyph. Message body/md in // inverse ink; an optional primary/sm/inverse button sits at the end. struct Snackbar: View { let message: String var action: String? = nil var body: some View { HStack(spacing: 10) { Image(systemName: "checkmark.circle.fill").font(.system(size: EandIcon.xl)) .foregroundColor(EandColor.alertMessageTextInfo) .frame(width: 44, height: 44) .background(EandColor.statusIndicatorSurfacePositive, in: RoundedRectangle(cornerRadius: EandRadius.radius5)) Text(message).font(.system(size: EandTypography.bodyMd.size)) .foregroundColor(EandColor.textDefaultInverse) Spacer(minLength: 0) if let action { InverseButton(title: action, size: .sm) {} } // white fill, ink label } .padding(.vertical, EandSpacing.spacing2xs) .padding(.leading, EandSpacing.spacing2xs).padding(.trailing, EandSpacing.sm) .frame(minHeight: EandScale.scale48) .background(EandColor.surfaceBaseMidnight) .clipShape(RoundedRectangle(cornerRadius: EandRadius.radius6)) } }
When to use
- Use to confirm, briefly and without blocking, the result of something the user just did:
a payment received, an add-on activated. Use
loaderwhile a short process runs. - Don't use for status that must stay on the page (use Alert), or for an outcome that deserves its own screen (use AlertModal or PageTitle).
Choosing a status
status | Tile | Glyph |
|---|---|---|
success | status-indicator/surface/positive | check-circle-filled |
alert | status-indicator/surface/warning (amber) | warning-filled |
warning | status-indicator/surface/danger (orange) | dismiss-filled |
info (default) | status-indicator/surface/neutral | info-filled |
loader | status-indicator/surface/neutral | A spinning ring |
Figma's alert is the amber step and its warning the orange one. Every V1.2 snack bar carries
a status tile; with no status, it shows info.
Anatomy
- Tile — a 44px status tile at the start.
- Message —
messageinbody/md, white.aedadds an amount, such as "AED 60.00", in SemiBold 14px right after it. - Action —
actionrenders a primarysminverse Button that callsonAction. - Backdrop —
backdroplays a soft gradient and blur behind the pill, so it reads over busy content.
<Snackbar status="success" message="Payment received" aed="AED 60.00" />
<Snackbar status="loader" message="Activating your add-on" />
<Snackbar status="alert" message="Your balance is low" action="Recharge" onAction={recharge} backdrop />Deprecated
toneis nowstatus:positivebecomessuccess,warningbecomesalert,dangerbecomeswarningandloadingbecomesloader.tone="default"still renders the old bare, centred message.subtitleandonDismisshave no V1.2 counterpart; the snack bar has one line and no dismiss control.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
message | ReactNode | — | |
action? | ReactNode | — | Label of the primary / sm / inverse button (Figma Show button). |
aed? | ReactNode | — | Figma aed-text — an amount after the message, e.g. "AED 60.00". |
backdrop? | boolean | — | Figma back-ground=yes: a blurred gradient scrim behind the pill, for busy content. |
onAction? | (() => void) | — | |
onDismiss? | (() => void) | — | Deprecated. The V1.2 snack bar has no dismiss control. |
status? | 'alert' | 'success' | 'warning' | 'info' | 'loader' | — | Figma .icon-snackbar-status axis. Takes precedence over tone. Default info. |
subtitle? | ReactNode | — | Deprecated. The V1.2 snack bar has no second line. |
tone? | 'default' | 'warning' | 'positive' | 'danger' | 'loading' | — | Deprecated. Use status. tone="default" still renders the old bare, centred message. |
Design
Figma source: Snack-bar — etisalat Consumer App DSL V1.2
- Pill:
surface/base/midnight, 16px radius (border-radius/6), padding 2/8/2/2, at least 48px tall, with a 10px gap that Figma leaves unbound. - Tile: 44px at a 14px radius (
border-radius/5), padding 6, holding a 24px filled glyph inalert-message/text/info. - Message:
body/mdintext/default/inverse; the amount sits 3px after it. - Backdrop: padding 0/16/32/16 and a 15% gradient from #3f3f3f to transparent, rising from the bottom. Figma's progressive blur (0 to 8) is approximated with a masked 8px blur.