Skip to content
The Membrane Palette
Feedbackbeta

Toast

A brief, polite confirmation of something the person just did — one live region per page, MembranePalette.toast() or a data-mp-toast button, auto-dismissed unless it's an error.

Examples

Tones

Draft saved

Last edit 2 minutes ago.

Workshop shared

Ana can now edit the syllabus.

Working offline

Changes will sync when you reconnect.

HTML for “Tones”
<div class="mp-toast-region" data-placement="inline" aria-live="polite">
  <div class="mp-toast" data-tone="success">
    <div class="mp-toast__content"><p class="mp-toast__title">Draft saved</p><p>Last edit 2 minutes ago.</p></div>
    <button class="mp-toast__close" type="button" aria-label="Dismiss">×</button>
  </div>
  <div class="mp-toast">
    <div class="mp-toast__content"><p class="mp-toast__title">Workshop shared</p><p>Ana can now edit the syllabus.</p></div>
    <button class="mp-toast__close" type="button" aria-label="Dismiss">×</button>
  </div>
  <div class="mp-toast" data-tone="warning">
    <div class="mp-toast__content"><p class="mp-toast__title">Working offline</p><p>Changes will sync when you reconnect.</p></div>
    <button class="mp-toast__close" type="button" aria-label="Dismiss">×</button>
  </div>
  <div class="mp-toast" data-tone="error" role="alert">
    <div class="mp-toast__content"><p class="mp-toast__title">Couldn't publish</p><p>The cohort is full. Nothing was lost.</p></div>
    <button class="mp-toast__close" type="button" aria-label="Dismiss">×</button>
  </div>
</div>

Triggered by a button

HTML for “Triggered by a button”
<div class="mp-cluster">
  <button class="mp-button" type="button" data-variant="secondary" data-mp-toast="Link copied" data-mp-toast-body="Paste it anywhere." data-mp-toast-tone="success">Copy link</button>
  <button class="mp-button" type="button" data-variant="ghost" data-mp-toast="Couldn't reach the server" data-mp-toast-tone="error">Simulate an error</button>
</div>

Guidance

Toasts confirm an action that already happened ("Draft saved", "Link copied"). They are announced politely, never steal focus, and leave on their own — so they must never carry the only copy of something the person needs. Anything that needs a decision is a Dialog; anything that explains state on the page is an Alert.

Showing a toast

components/membrane.js exposes one function and one declarative hook:

MembranePalette.toast({ title: 'Draft saved', body: 'Last edit 2 minutes ago.', tone: 'success' });
// options: title (required), body, tone: 'info' | 'success' | 'warning' | 'error', timeout (ms; 0 = stays)

<button class="mp-button" data-mp-toast="Link copied" data-mp-toast-tone="success">Copy link</button>

It creates the .mp-toast-region live region on first use. Toasts stay 6 seconds (longer while hovered or focused); errors stay until dismissed, so nobody misses them. They enter with --transition-enter and leave with the faster --transition-exit — membrane.js sets the runtime-only data-leaving attribute during the exit; never author it.

Accessibility

  • The region is a polite live region; error toasts use role="alert".
  • Toasts never take focus. Errors persist until dismissed; others pause their timer while hovered or focused (WCAG 2.2.1).
  • The close button needs aria-label="Dismiss"; it's 36px, above the 24px minimum.
  • Don't put the only route to an action in a toast — it may be gone before someone reaches it.

Manual screen-reader and usability checks have not been recorded for this inventory. See the accessibility evidence for automated coverage, remaining checks and the result-recording protocol.

API

Toast classes
ClassKind
.mp-toast-regionroot
.mp-toastroot
.mp-toast__contentpart of .mp-toast
.mp-toast__titlepart of .mp-toast
.mp-toast__closepart of .mp-toast
Toast attributes
AttributeValues
data-leavingboolean — presence enables it
data-tonesuccess · warning · error
data-placementinline

States styled: :focus-visible :hover. Set the native attribute or ARIA state; there are no state classes.

Toast component tokens
TokenDefaultLight · dark
--mp-toast-accentvar(--color-info)#1B756D · #3AAFA8
--mp-toast-titlevar(--color-text-primary)#2A2622 · #F0EBE1

Design tokens consumed: --border-default --border-width-thick --color-bg-elevated --color-bg-hover --color-error --color-error-text --color-info --color-success --color-success-text --color-text-primary --color-text-secondary --color-warning --color-warning-text --elevation-overlay --focus-ring --focus-ring-offset --font-sans --leading-small --radius-full --radius-md --size-control-sm --size-touch-target --space-1 --space-2 --space-3 --space-4 --space-6 --text-body --text-small --transition-enter --transition-exit --weight-semibold --z-toast

Verified contrast

The build measures each pair for the defaults and for every tone, variant and state that reassigns a token, over page and card surfaces. The ratios below are the worst case in each mode; a pair below its minimum stops the build.

Toast contrast pairs
UsePairLightDarkMinimum
toast title--mp-toast-title on --color-bg-elevated5.685.564.5

Source