Skip to content

Snackbars

components specs/components/snackbars.kmd

Transient feedback message at the bottom of the screen — confirms an action, optionally offers a single action (undo, retry). Material parity (`/components/snackbars`). Distinguished from banner (persistent) and dialog (modal).

When this spec applies

Primary triggers

All triggers

Specification body

Spec — Snackbars

Facet Visual of Koder Design. Material parity: https://m3.material.io/components/snackbars.

Where they fit

ComponentModalityPersistenceAction count
SnackbarNon-modalTransient (4-10 s)0 or 1
BannerNon-modalPersistent until dismissed0-2
DialogModalUntil dismissedUnlimited

Use snackbar for low-priority, transient confirmation. Switch to banner for persistent attention or dialog for blocking interaction.

Anatomy (with action)

   ┌────────────────────────────────────────────────┐
   │  File moved to Trash.              UNDO        │
   └────────────────────────────────────────────────┘
        ↑                                ↑
       message                        action
  • Container width: min 344 dp / max 672 dp; on Compact width fills minus 16 px margin each side
  • Height: 48 px (single line) / 68 px (two lines) / auto for longer
  • Padding: 16 px horizontal, 14 px vertical
  • Corner radius: 4 px
  • Container bg: inverse-surface (high contrast — light bg in dark mode, dark bg in light mode)
  • Message: body-medium (14/20, weight 400), color inverse-on-surface
  • Action: text button, inverse-primary color, weight 600
  • Elevation: 3 dp

R1 — Placement

SurfacePosition
Compact (mobile)Bottom-centered, 16 px from bottom safe-area
Medium / ExpandedBottom-left, 16 px from edges
Large (desktop wide)Bottom-left (default); allow bottom-right via prop

Snackbar floats above app content but BELOW navigation bars (bottom app bar, navigation bar). Anchor offset must account for bottom nav height + safe-area inset.

R2 — Duration

Snackbar typeDefault durationNotes
Plain message (no action)4 s"File saved."
With action (e.g., "UNDO")6 sGives user time to act
Long / important10 sCap at 10 s — beyond, use banner
IndefiniteOff by defaultOnly when user must act (rare)

Pause timer on hover / focus / prefers-reduced-motion: reduce (no auto-dismiss in that case — show close × instead).

Reduced motion: still auto-dismisses, but no slide animation.

R3 — Actions

  • 0 actions: snackbar acts as confirmation; tap snackbar dismisses
  • 1 action: text button on right (UNDO, RETRY, VIEW); tap action triggers callback + dismisses
  • 2+ actions: NEVER. Switch to dialog or banner.

Action labels:

  • Single-word imperative when possible: UNDO, RETRY, VIEW, DISMISS
  • All caps OR Title Case — pick one style per app and stick to it
  • Color: inverse-primary (high contrast against inverse surface)

R4 — Two-line variant

When message is longer than fits on one line:

   ┌────────────────────────────────────────────────┐
   │  Sync failed. Check your network and retry.    │
   │                                  RETRY  ×      │
   └────────────────────────────────────────────────┘
  • Action moves to second line, right-aligned
  • Optional close × button (added for error / important snackbars)
  • Container grows to 68 px

Never exceed 2 lines. Truncate or escalate to banner / dialog.

R5 — Queue behavior

Multiple snackbars: queue them.

  • Current snackbar finishes its duration (or user dismisses) → next pops up
  • New snackbar with same content while a same-content one is showing: reset its timer (don't queue duplicate)
  • Maximum visible: ALWAYS 1 — never stack snackbars

Programmatic dismissal: API to dismiss current immediately (e.g., on route change to clear stale snackbars).

R6 — Animation

  • Enter: slide-in from bottom edge (motion-medium, ~250 ms emphasized)
  • Exit: slide-out down + fade (motion-fast, ~150 ms)
  • Action tap: snackbar fades while action runs
  • Reduced motion: instant in / out; no slide

R7 — Dismissal

TriggerResult
Timer elapsesAuto-dismiss
User taps snackbar (no action variant)Dismiss
User taps action buttonRun action + dismiss
User taps × (two-line variant)Dismiss (no action)
User swipes (touch)Dismiss (mobile gesture)
Esc key (keyboard focus on snackbar)Dismiss
ProgrammaticDismiss

R8 — Accessibility

  • Container: role="status" (info) OR role="alert" (error)
  • aria-live="polite" (status) / assertive (alert)
  • Action button: clear label ("Undo move to trash", not just "Undo" if context is unclear)
  • Close × button: aria-label="Dismiss"
  • Screen reader announces full snackbar content + action label on appearance
  • Don't auto-focus snackbar (would steal focus from user task)
  • Don't rely on color (action is also bold text + button hit target)

R9 — Tone

Snackbars are intentionally neutral in tone. Don't tonally style with error / warning / success backgrounds — that's banner territory. Snackbar bg is always inverse-surface (high-contrast neutral).

If you need to express tone (error, warning), use a banner or dialog.

R10 — Density

DensityHeight (single)Padding
Compact40 px12 px / 8 px
Default48 px16 px / 14 px
Comfortable56 px20 px / 18 px

R11 — Per-preset variation

PresetContainerAction color
material3inverse-surface 4 px radiusinverse-primary
material2Dark gray 2 px radiusAccent color
ios_cupertinoRounded toast with blur backdropSystem blue
gnomeAdwaita In-app notification, slide from topAccent
windows_11Mica notification toastAccent
brutalistSharp black bg, white textInverted action button
terminal_classicSingle-line [msg] <UNDO> at bottomUnderlined action

R12 — Forbidden patterns

  • ❌ More than 1 action button
  • ❌ Stacking snackbars (queue or replace, never stack)
  • ❌ Snackbar with > 2 lines of text
  • ❌ Snackbar > 10 s (use banner instead)
  • ❌ Snackbar < 4 s (too brief to read for slow / impaired readers)
  • ❌ Auto-focus / focus trap (would interrupt user)
  • ❌ Tonal bg color (use neutral inverse-surface)
  • ❌ Snackbar with form inputs / interactive widgets (snackbar is for confirmation, not input)
  • ❌ Snackbar that requires reading to use the app (use dialog if blocking)
  • ❌ Snackbar without safe-area bottom inset on iOS / Android gesture-nav
  • themes/elevation.kmd — 3 dp tonal + shadow recipe
  • themes/color-roles.kmdinverse-surface / inverse-on-surface / inverse-primary tokens
  • themes/motion.kmd — emphasized easing for enter
  • themes/typography.kmdbody-medium for message
  • app-layout/safe-area.kmd — bottom inset rule
  • components/banners.kmd — persistent sibling
  • components/dialogs.kmd — modal sibling
  • foundations/elements.kmd — Marker family

References