ComponentsToast

Toast

component

Transient confirmations — the toned variants and the actionable snackbar.

Toast
Trigger a sample notification.
Best practices
Do
  • A passive confirmation uses the toned variants (.toast--success/info/warn/error) and auto-dismisses.
  • An actionable toast ('Saved — Undo') is the snackbar: .toast--snackbar on the inverse surface, ONE .toast__action, one at a time.
  • Anchor the stack in one corner via .toast-stack and cap it at about three visible.
Don't
  • Don't use a toast for anything that needs a decision — that is a .dialog.
  • Don't auto-dismiss a toast that carries an action.
Trigger a toast above ↑

Best practices

Do
  • A passive confirmation uses the toned variants (.toast--success/info/warn/error) and auto-dismisses.
  • An actionable toast ('Saved — Undo') is the snackbar: .toast--snackbar on the inverse surface, ONE .toast__action, one at a time.
  • Anchor the stack in one corner via .toast-stack and cap it at about three visible.
Don't
  • Don't use a toast for anything that needs a decision — that is a .dialog.
  • Don't auto-dismiss a toast that carries an action.

Recipe CSS

This is the exact CSS your kit ships for Toast — token-driven, so it re-themes with every knob. Get it (and the rest) from the configurator's Use kit panel.

/* === Toast stack ===
   In production this stack pins bottom-right of the viewport (use position:
   fixed + bottom/right). In the gallery demo it lives inside a bordered
   .toast-demo-frame with trigger buttons — clearly a sandbox, not chrome.
   The tone-coded left border + dismiss button are the actual pattern;
   positioning is a consumer concern, not a token concern. */
.toast-demo-frame {
  position: relative;
  min-height: 110px;
  border: 1px dashed var(--k-border);
  border-radius: var(--k-radius-md);
  background: var(--k-surface-sunken);
  padding: var(--k-s-10);
  display: flex;
  align-items: flex-end;
  overflow: hidden;
}
.toast-demo-frame__empty {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: var(--k-type-eyebrow);
  color: var(--k-fg-faint);
  pointer-events: none;
}
.toast-stack {
  display: flex;
  flex-direction: column-reverse;
  gap: var(--k-s-6);
  align-items: stretch;
  width: 100%;
}
.toast {
  display: flex;
  align-items: flex-start;
  gap: var(--k-s-10);
  padding: var(--k-s-10) var(--k-s-12);
  background: var(--k-surface-overlay, var(--k-surface-raised));
  border: var(--k-hairline, 1px solid var(--k-border));
  border-radius: var(--k-radius-md);
  box-shadow: var(--k-shadow-md);
  font-size: var(--k-type-small);
  animation: var(--k-anim-slide-up, k-slide-up 240ms ease) backwards;
}
.toast--success { border-left: 3px solid var(--k-success); }
.toast--info    { border-left: 3px solid var(--k-info); }
.toast--warn    { border-left: 3px solid var(--k-warning); }
.toast--error   { border-left: 3px solid var(--k-danger); }
.toast__body { flex: 1; min-width: 0; }
.toast__title { font-weight: var(--k-weight-semibold); }
.toast__sub { color: var(--k-fg-muted); font-size: var(--k-type-small); margin-top: 1px; }
.toast__close {
  background: transparent;
  border: 0;
  padding: var(--k-s-2);
  cursor: pointer;
  color: var(--k-fg-muted);
  display: inline-flex;
  border-radius: var(--k-radius-md);
  transition: background var(--k-dur-fast, 120ms) var(--k-ease, ease), opacity var(--k-dur-fast, 120ms) var(--k-ease, ease), color var(--k-dur-fast, 120ms) var(--k-ease, ease);
}
.toast__close:hover { color: var(--k-fg); background: var(--k-state-hover); }
/* Inline text action ("Undo", "Retry") — sits after the body, before the
   dismiss ✕. On a regular toast it's primary-tinted; the snackbar recolors
   it below. NEVER make the action "Dismiss" — that's what the ✕ is for. */
.toast__action {
  background: none;
  border: 0;
  padding: var(--k-s-2) var(--k-s-6);
  border-radius: var(--k-radius-sm, 6px);
  font: inherit;
  font-size: var(--k-type-small);
  font-weight: var(--k-weight-semibold);
  color: var(--k-primary);
  cursor: pointer;
  flex: none;
}
.toast__action:hover { background: var(--k-state-hover); }
/* Snackbar (H4) — the M3 snackbar CONTRACT on the toast primitive. Look:
   INVERSE surface (the H1 inverse roles — guaranteed contrast on any theme),
   no tone border (a snackbar is neutral app feedback, not a status), one
   optional text action in inverse-primary. Behavior contract (consumer-
   owned): one line, ONE action max, auto-dismiss 4-10s, and one snackbar at
   a time — queue them, never stack. */
.toast--snackbar {
  background: var(--k-inverse-surface);
  color: var(--k-inverse-fg);
  border-color: transparent;
  align-items: center;
}
.toast--snackbar .toast__sub { color: var(--k-inverse-fg); opacity: 0.72; }
.toast--snackbar .toast__action { color: var(--k-inverse-primary); }
.toast--snackbar .toast__action:hover { background: transparent; text-decoration: underline; text-underline-offset: 3px; }
.toast--snackbar .toast__close { color: var(--k-inverse-fg); opacity: 0.75; }
.toast--snackbar .toast__close:hover { color: var(--k-inverse-fg); background: transparent; opacity: 1; }