Patterns Toast notification

Toast notification

A brief, dismissable status message that appears in response to an action and disappears on its own. The trick is announcing it to assistive tech without ripping focus away from what the user was doing.

Reviewed against the methodology checklist Updated

Try the keyboard

When to use

A toast is the right answer for brief, non-blocking confirmation of an action the user just took. “Saved.” “Sent.” “Copied to clipboard.” The user doesn’t need to do anything; we’re just acknowledging.

Don’t use a toast for:

The pattern

Accessible toast (live region)

The trick to an accessible toast is the live region — a container with aria-live whose content changes are announced by screen readers without focus moving:

HTML
<!-- Polite: queues behind whatever the user is currently being told -->
<div role="status" aria-live="polite" aria-relevant="additions text" id="toast-region"></div>

<!-- Assertive: interrupts. Reserve for genuine errors. -->
<div role="alert" aria-live="assertive" aria-relevant="additions text" id="toast-region-alert"></div>

The regions are present empty, on every page. When you append a child to one, the screen reader announces the added text:

JS
function toast(message, { variant = 'info' } = {}) {
const region = document.getElementById(
  variant === 'error' ? 'toast-region-alert' : 'toast-region'
);
const el = document.createElement('div');
el.className = `toast toast--${variant}`;
el.textContent = message;
region.appendChild(el);
setTimeout(() => el.remove(), 6000);
}

Polite vs assertive

Use forWhat it does
aria-live="polite" (role="status")Most things — “Saved”, “Copied”, confirmationsQueued; interrupts nothing
aria-live="assertive" (role="alert")Genuine errors that the user must hear right nowInterrupts current speech

Default to polite. Assertive announcements interrupt whatever the screen reader was reading; overuse of them is exhausting. The error toast in our demo uses role="alert" because failed saves are worth interrupting for; the others are polite.

Don’t move focus

A toast is a passive notification. Moving keyboard focus to it yanks the user out of whatever they were doing — usually the worst possible UX, especially mid-form-fill. The live region announces the message; focus stays put.

If the user wants to act on the toast (dismiss it, click “Undo”), they can Tab to it — the dismiss button is in the tab order after the trigger, so the discovery flow works.

Dismiss + auto-dismiss

WCAG 2.2.1 says timing must be adjustable. Auto-dismissing toasts have a timer; here’s how to stay compliant:

Stack management

If multiple toasts arrive in quick succession, render them all in the region. The screen reader announces each as it arrives. Visually, stack them with the newest at the top. Cap the visible count (4–5) and drop the oldest off-screen visually if needed; the live region will have already announced them.

Anti-patterns

A <div> that just appears

HTML
<div class="toast">Settings saved.</div>

No role, no live region, no announcement. Sighted users see it; screen-reader users have no idea the save happened. The fix is one attribute: role="status".

Live region created on demand

JS
// DON'T — screen readers may not register the region
const live = document.createElement('div');
live.setAttribute('aria-live', 'polite');
live.textContent = 'Saved!';
document.body.appendChild(live);

Live regions need to be in the DOM before their content changes. Most screen readers don’t announce a region that didn’t exist when the page loaded. Render the empty region in your layout; populate it as needed.

Auto-dismissing in 2 seconds

A toast that appears for 1.5 seconds is invisible to slow readers, anyone using magnification, or screen-reader users who haven’t finished hearing the previous announcement. Five seconds minimum, with hover/focus pausing it.

Assertive everything

aria-live="assertive" interrupts the user. If your “Saved” toast interrupts the user’s screen reader mid-sentence, they hate you. Reserve it for actual errors that need attention now.

Common variations

Checklist

Screen reader transcript

Voiced by George — reading what VoiceOver on macOS Safari announces. Other readers (NVDA, JAWS) phrase things differently; the meaning is what matters.

Screen reader announcements for each step
ListenYou doScreen reader says
Activate the "Trigger success" button(focus stays on the button) Settings saved.
Tab forwardDismiss notification, button.
Press Enter(toast removed; focus returns to a sensible nearby control)

Screen reader transcript — anti-pattern

Same interaction, but on the broken version above. Notice what the user is missing.

Screen reader announcements for each step
You doScreen reader says
Activate a trigger(toast appears visually, no announcement at all — screen-reader users have no idea anything happened)
Sometimes(focus is moved into the toast — user is yanked out of their workflow)

WCAG references