v3.0.0
Snackbar

The actionable toast: a pill that slides in from the bottom, delivers one short message with an optional icon and an optional action button, and dismisses itself after 4 seconds — or earlier, on a downward swipe.

3.0.0 3.0.0 -- 3.0.0
Snackbar message

Overview

  • 1
    Inform
  • 2
    Custom
  • 3
    Button aside
  • 4
    Button below
Snackbar message
1
Snackbar message
2
Snackbar message
3
Snackbar message
4

States

Inform

Snackbar message
1
2
3
4
5
  • 1
    Background --background-inverse-primary — the inverse surface: a dark pill on the light theme, a light pill on the dark.
  • 2
    Icon --text-and-icon-inverse-primary; the default glyph is warning-outline.
  • 3
    Description --text-and-icon-inverse-primary — the content colour.Body/Compact Body — the text style.
  • 4
    Button Fill --background-primary — deliberately counter-phase to the Inform pill: the dark theme turns the pill light and the button dark, the pair never merges.
  • 5
    Button Label --text-and-icon-primary — the label colour.Heading/Heading 4 — the customButton base default.

Custom

Snackbar message
1
2
  • 1
    Background --snackbar-fill — the instance's semantic token (here --accent-green2).Illustrative only — the instance owns the ≥ 4.5:1 check; this pairing, like every accent + AlwaysLight, measures below it (3.83 / 2.78).
  • 2
    Icon and Description --snackbar-content — the instance's semantic token (here --text-and-icon-always-light).

Anatomy

Snackbar message
1
2
3
4
5
  • 1
    The component root var(--sp-s16) — the side margins, per side. The root spans the full screen width and brings them with it. Required.
  • 2
    ContentContainer var(--sp-s20) — roundness.var(--sp-s8) — padding, all four sides.The visible pill carrying the tone fill; fixed heights — 56, or 108 with the button below. Required.
  • 3
    IconContainer var(--sp-s24) — the glyph, painted via currentColor; the default is warning-outline for both styles.var(--sp-s32) × var(--sp-s40) — the invisible box, with the glyph at its var(--sp-s8) inline-start inset. The inset exists because the pill padding is only s8 — sized for the button — while the glyph keeps the toast family's 16 from the edge: 8 + 8. The slot pays the difference, not the pill.Hidden entirely with Show Icon off. Optional.
  • 4
    Description Body/Compact Body — the text style.var(--sp-s8) — the slot's own side insets.Up to 2 lines at 100 % scale; unclamped in the 130 / 150 % accessibility modes. Required.
  • 5
    ActionButton var(--sp-s40) — height; the width hugs the label.var(--sp-s10) — roundness, instance-set.The open customButton base, preset custom-button. Off by default; its dock follows Button position and the adaptive rule. Optional.

Layout

Measured specimen

Snackbar message
1
Snackbar message
2
  • General var(--sp-s56) — height, fixed. The token itself scales with the SP modes — 56 → 72.8 → 84 at 130/150 % — so when the client scales the UI, the extra lines fit the way they do on Notification.var(--sp-s8) — pill padding, all four sides.var(--sp-s20) — roundness, all four corners.var(--sp-s16) — the root's own side margins, both sides.var(--sp-s4) — the container gaps. With the parts' own s8 insets below they compose the visual 12s — glyph → text and text → button.
  • 1
    IconContainer var(--sp-s32) × var(--sp-s40) — the box, fixed.var(--sp-s8) — the inline-start inset. The pill padding is sized for the button, so the slot pays the difference: 8 + 8 returns the glyph to the family's 16 from the edge.var(--sp-s24) — the glyph: vertically centred, flush to the box's inline end.
  • 2
    StartText var(--sp-s8) — the slot's own insets, both sides.var(--sp-s40) — the row it centres in vertically; the width fills whatever the row leaves.Body/Compact Body — the line, hugging its own height within the centred slot.

Vertical — button below

Snackbar message
  • General 108 — the second fixed height. Annotation arithmetic, not a token: 8 + 40 + 8 + 40 + 12.var(--sp-s8) — the gap between the content row and the button row.12 — the bottom air: the var(--sp-s8) padding plus the button row's own 4 — the one asymmetry the composition carries.

RTL

مُلصَق
  • General The rows mirror from the document's dir — the flex order reverses on its own, and the icon inset and the Below indent are logical (inline-start), so they flip with it.Nothing flips in place: warning-outline is not on the icon-container.md § 3.5 directional list. The mirrored composition is a variant of the Figma set (RTL: Off | On).

Animation

Lifecycle

Snackbar message
Live — enter from the bottom, 4 s hold, exit, on a loop
  • General var(--transforming-enter-default) — enter, translateY(100% → 0) from past the bottom edge.var(--transforming-exit-default) — exit, back down. Fires at the 4 s timeout, on a downward swipe, on the action, or when a new message replaces the current one.Only transform takes part, so the slide stays on the compositor — layout, colour and height never animate. The timing matches Notification and HeaderAlert — one entrance for the family of edge banners.
  • Reduced motion Handled at the token: motion.css zeroes every --transforming-* inside prefers-reduced-motion: reduce, so the pill appears and leaves instantly and this component carries no override of its own.

Adaptive dock

Message deleted
Live — the dock follows the message length
  • General The dock is measured, not animated: the component decides Aside or Below BEFORE the pill enters, and nothing moves mid-flight.The reference measure: in the Aside dock the description's rendered height against two line-heights — overflow relocates the button below, and only a message that overflows 2 lines at full width earns the ellipsis.
  • Button press var(--component-push-button-press) — the nested Button's own press, scale 100 % → 95 %.var(--component-push-button-release) — release, back to 100 %. pushButton belongs to the Button component — the snackbar adds nothing of its own.

Usage

  • 1
    One small recovery A transient message that offers one follow-up: an undoable outcome ("Message deleted" + Undo), a retryable step. One button — a decision with alternatives belongs in a dialog; without the button, prefer Notification for pure statuses.
  • 2
    Errors are Notification's job The bottom toast has no error tone by design — every failure surfaces as a Negative Notification at the top, where it is seen. Tinting Custom red does not make it one: Custom is a tint, never a meaning.
Message deleted
✓ An undoable outcome with one small recovery — the snackbar's job
Payment failed
✕ An error — that is a Negative Notification at the top, not a bottom toast

Accessibility

Snackbar message
role="status" — always polite: errors arrive as a Notification
Message deleted
The action — the component's only tab stop
1
2
  • 1
    Announced Once, Focus Stays Put The message row (icon + description) is the live region — polite for both styles, since errors live in Notification and no Snackbar interrupts current speech; the pill root and the button sit outside it. TalkBack: fires once on appearance, never steals focus, stays reachable by swipe navigation and touch exploration. VoiceOver: DsSnackbarAlert posts a UIAccessibility announcement; focus stays where the user is.
  • 2
    The Action Is the One Tab Stop A real focusable Button — the component's only one. The entry announcement carries the message text alone; the action is discovered by swipe navigation after it, so a message whose action must be known immediately says so in its own words ("Message deleted — undo available").
  • Dismiss Without the Gesture TalkBack exposes the standard ACTION_DISMISS in the pill's actions menu; VoiceOver implements accessibilityPerformEscape() (the two-finger Z scrub) — each the non-gesture equivalent of the downward swipe.
  • The Timeout Waits for the Reader While a screen reader is active the 4 s auto-dismiss extends until the announcement has finished — and long enough to reach and press the action. Open gap, recorded in the spec: keyboard and motor-impaired users without a screen reader get no extension (WCAG 2.2.1 is not screen-reader-scoped).
  • Focus Never Drops If focus is on the action when the pill leaves — on any exit path: replace, timeout, or swipe — it returns to the user's previous position rather than being dropped with the removed node.
  • Web: Keep the Region Mounted The live-region container stays mounted (empty) and each message mutates only its text — inserting a fully-populated region in one DOM mutation is not reliably announced. The region is the message row, not the root — the button is a sibling OUTSIDE the aria-live node, so the message alone drives the announcement and the label is never double-spoken.
  • Touch Target and Contrast The action is var(--sp-s40) tall — below the DS var(--sp-s44) floor and the 48 of WCAG 2.5.5; Button's dense-context rationale does not obviously apply to a floating pill — the owner's call before Ready. Contrast: the Inform pairing (17:1) and the button pair are fine; a Custom instance supplies its own semantic pair and owns the ≥ 4.5:1 check.