Dev view
Toast
A transient floating notification anchored to a corner of the viewport, auto-dismissing after a short visible duration. Distinct from Alert (inline, persistent) by its ephemerality and positioning; distinct from Modal (blocking) by its non-modal contract. Used for success confirmations after asynchronous actions, transient status messages, undoable operations, and short notifications that do not require explicit acknowledgement.
When to use
Use
For transient confirmations after asynchronous actions ("Saved", "Copied"), undoable operations ("Item deleted · Undo"), and short non-essential status updates the user can safely miss. Toast is non-blocking and auto-dismisses; users do not need to acknowledge.
Avoid
For critical errors requiring user action — that is `Alert` (inline persistent) or `Modal` (blocking). For long informational content — that is `Alert` or page prose. For on-demand description — that is `Tooltip`. For page-wide persistent notices — that is `Banner`.
Versus related
- alert
`Alert` is inline and persistent; `Toast` is floating and auto-dismissed. Alert is for situations the user may need to revisit or act on; Toast is for transient signals the user can miss without consequence.
- modal
`Modal[variant=alertdialog]` is blocking and demands explicit response; `Toast` is non-blocking and ephemeral. They occupy opposite ends of the notification-urgency spectrum.
- banner
`Banner` is page-wide, persistent, and informational (e.g. a maintenance notice at the top of every page); `Toast` is corner-anchored, ephemeral, and action-triggered. Banner is system-level; Toast is action-level.
- tooltip
`Tooltip` is hover/focus-revealed descriptive text; `Toast` is system-pushed notification. Tooltip is pulled by the user; Toast is pushed by the system.
Code anatomy
| Slot | Code slot | Semantic |
|---|---|---|
viewport | viewport | presentational-region |
container | container | status-or-alert |
icon | icon | presentational |
title | title | strong-or-heading |
body | body | prose |
action | action | button |
dismiss-button | dismiss | button |
Variants, properties, states
Variants
Structurally different versions of the component.
infosuccesswarningerror Properties
The same component, parameterised.
| Property | Type |
|---|---|
position | top-start | top-end | bottom-start | bottom-end | top-center | bottom-center |
dismissible | boolean |
hasAction | boolean |
hasIcon | boolean |
States
Browser/user-driven (interactive) vs. app-driven (data).
| Kind | States |
|---|---|
interactive | hoverfocus-visible |
data | openingopenpausedclosingclosed |
State transitions
| From | To | Trigger |
|---|---|---|
closed | opening | Consumer triggers the toast (typically after an async operation completes). The toast is mounted in the viewport region; the auto-dismiss timer is initialised but not yet started. |
opening | open | The slide-in animation completes (or, under prefers-reduced-motion reduce, immediately). The auto-dismiss timer starts; the live region announces the toast content. |
open | paused | User hovers anywhere inside the toast viewport region OR focus moves into the toast region. The auto-dismiss timer pauses for all toasts in the viewport, not just the hovered one. |
paused | open | User leaves the viewport region (pointer and focus both out). The auto-dismiss timer resumes from where it paused (NOT restarted from full duration — the elapsed time before pause counts). |
open | closing | The auto-dismiss timer expires; or the user presses Escape with focus inside the toast region; or the user activates the dismiss button or invokes the action; or the consumer programmatically closes the toast. |
closing | closed | The slide-out animation completes (or immediately under reduced motion). The toast is removed from the viewport and from the live region. Subsequent toasts in the stack reflow. |
Cross-framework expression
| Framework | Structure mechanism | Variant mechanism |
|---|---|---|
| Web Components | A `<ui-toast-viewport>` host wrapping `<ui-toast>` children; viewport handles stacking and pause-on-hover; toast carries severity attribute reflected to role | attributes (`severity="success"`, `position="bottom-end"`, `dismissible`, `auto-dismiss-ms="5000"`); `data-state="opening|open|paused|closing|closed"` |
| React | Radix Toast (`Toast.Provider` / `Toast.Viewport` / `Toast.Root` / `Toast.Title` / `Toast.Description` / `Toast.Action`); React Aria `useToastRegion` plus `useToast`; or Sonner library which composes its own viewport | props with class-variance-authority for severity; `duration` prop for auto-dismiss; `position` on the viewport |
| Angular (signals) | Angular CDK Overlay for the viewport positioning plus `MatSnackBar` (or custom service) for queued toasts; signal-based toast state | input<'info' | 'success' | 'warning' | 'error'>(); service-level `position` and `duration` defaults |
| Vue | Headless UI does not ship Toast as of 2026-04; third-party (vue-sonner, primevue Toast); custom composable `useToast` plus a singleton viewport component | defineProps with literal-union types; service-level configuration |
Events
openChangedismissactionInvoke
Performance thresholds
stackDepthvisible-toast-count≥3toastsThe canonical maximum of visible toasts in the viewport is 3. Above this threshold, SR announcement floods occur and the viewport overflows on common screen sizes. Beyond 3, queue new toasts and reveal them as existing toasts dismiss. Mobile drops the threshold to 2 (see responsive).
autoDismissDurationvisible-time≥5000msThe canonical default auto-dismiss duration is 5 seconds. Below 3 seconds users cannot reliably read the message; above 8 seconds the screen real estate cost outweighs the benefit. The 5000ms default is reachable from `Sonner` / Radix Toast / React Aria defaults. Long-text locales may extend per the i18n textExpansion formula.
Accessibility
| Slot | Accessibility hint | |
|---|---|---|
viewport | Apply `role="region"` with `aria-label="Notifications"` so SR users can navigate to the toast region by landmark. The region itself is not a live region — individual toasts inside carry their own polite or assertive live-region roles depending on severity. Hover anywhere inside the viewport pauses the auto-dismiss timers of all visible toasts. | |
container | Apply `role="status"` (polite, default) for info and success severities, or `role="alert"` (assertive) for error severities. Warning sits on the boundary — canonical default is polite to avoid interrupting the user's work. Both roles imply implicit live regions. | |
icon | Decorative — `aria-hidden="true"`. Severity is communicated through the `role` and the visible body text, never through the icon glyph alone. | |
title | Plain `<strong>` or styled `<p>`; heading semantics not required for transient toasts. SR announces the title followed by the body in DOM order. | |
body | Plain prose. Capped at one to two sentences by canon. Anything longer should be an Alert. | |
action | Real button with accessible name. Receives focus when the user tabs into the toast region (after the dismiss button); pressing Tab exits the region. Activation triggers the consumer-provided handler and typically dismisses the toast as a side effect. | |
dismiss-button | Provide an accessible name ("Dismiss" or "Dismiss notification"). Activation removes the toast from the viewport and from the live region. Escape key (when toast region has focus) does the same. |
Accessibility acceptance
Keyboard walk
| Keys | Expected |
|---|---|
F6 (when supported by browser/OS) | Cycles focus to landmark regions including the toast viewport. Allows keyboard users to reach the toast region without tabbing through the entire page first. |
Tab (within the toast viewport) | Focus moves through visible toasts in DOM order — newest toast first by canonical convention (the one most recently announced). Within each toast, focus moves through action first then dismiss button. |
Escape (focus inside toast viewport) | Dismisses the focused toast (or most recent if none focused). Focus moves to the next focusable in the viewport, or back out to the document if no other toast remains. |
Enter or Space (focus on action button) | Invokes the action; toast dismisses with `source: 'action'`. Consumer handler runs. |
Enter or Space (focus on dismiss button) | Dismisses the toast immediately with `source: 'closeButton'`. |
Screen-reader announcements
| Trigger | Expected |
|---|---|
| Polite-severity toast appears (info, success, warning) | SR queues the announcement after the current one completes. Reads the role ("status") followed by title and body in DOM order. Does not interrupt the user's current task. |
| Assertive-severity toast appears (error) | SR interrupts the current announcement and reads the toast immediately. Reads "alert" followed by title and body. Used sparingly — assertive is for genuinely urgent situations. |
| User hovers the viewport, timer pauses | No announcement — the pause is internal state. SR users can re-read by navigating to the toast region's content. |
| Toast auto-dismisses or is closed | No "dismissed" announcement; the silence (and removal of the live-region content) confirms the toast is gone. |
axe-core rules to assert
aria-allowed-rolearia-required-attrcolor-contrastrole-img-altlandmark-unique
Common mistakes
#toast-no-pause-on-hover
Auto-dismiss continues while the user reads
The toast slides in, the user starts reading, the timer fires, the toast slides out. Users with motor impairments, cognitive impairments, or simply slow reading speed cannot reliably consume the message. WCAG 2.2.1 (Timing Adjustable) is failed.
Pause the auto-dismiss timer on pointer-enter and focus-into the viewport region. Resume on pointer-leave AND focus-out (both must be true). Some implementations pause on individual toast hover; canonical pauses on viewport-level hover so users can move between adjacent toasts.
#toast-stack-overflow
Toast stack grows unbounded
Multiple toasts fire in rapid succession; the stack grows to 5, 10, 20 toasts. SR users hear a torrent of announcements; pointer users see the screen filled with notifications. The viewport overflows.
Cap the canonical stack depth at 3 visible toasts. Beyond that, queue new toasts and only render them when an existing toast dismisses. Document the threshold in performance. The queue is invisible — users do not know how many toasts are pending.
#toast-essential-info
Critical errors delivered as toast
A network failure or data-loss warning is shown as an auto-dismissing toast. The user misses it (auto-dismiss); the underlying problem persists; data is lost without recourse.
Critical errors that require user action are Alert (inline persistent) or Modal (blocking). Toast is reserved for transient confirmations and non-essential updates the user can miss without consequence. Document the canonical severity-to-component map: success and info → toast or alert; warning → alert; error requiring action → alert or modal.
#toast-aria-live-assertive-for-info
Info-severity toast uses assertive live region
Toasts carry `role="alert"` (assertive) regardless of severity. SR users are interrupted for every "Saved" / "Copied to clipboard" confirmation; the assertive flood makes them disable notifications entirely.
Match severity to live-region politeness: info / success → `role="status"` (polite), error → `role="alert"` (assertive), warning is canonical-default polite (re-evaluate per use case). Document the mapping; reserve assertive for content that genuinely interrupts.
#toast-no-keyboard-dismiss
Escape does not dismiss the focused toast
Keyboard users tabbing into the toast region cannot exit via Escape — the only way to dismiss is to tab to the dismiss button and activate, or wait for auto-dismiss. The keyboard contract feels broken compared to other light-dismiss patterns (Popover, Tooltip).
Bind Escape on the viewport region: when focus is inside the toast region, Escape dismisses the focused toast (or the most recent toast if none is focused). Document the keyboard contract in a11yAcceptance.
Figma↔Code mismatches
- 01 Figma
A toast drawn next to the trigger that surfaced it
CodeA toast rendered in a fixed-position viewport region at a corner of the screen
ConsequenceDesigners may anchor toasts to specific UI elements in mocks (next to the save button, below the form). Implementations following the Figma file create per-trigger floating surfaces that compete with each other and miss the stacking, the auto-dismiss, and the live-region semantics.
CorrectToast lives in a single viewport region per page (or per window scope), not anchored to triggers. The position property selects which corner; the viewport region handles stacking and live-region semantics. Document the singleton viewport contract explicitly.
- 02 Figma
Toast auto-dismiss drawn as a single visual state with no progress indicator
CodeAn auto-dismiss timer driving slide-out at a configurable duration
ConsequenceDesigners may not realise the toast disappears automatically; developers ship without a progress affordance and users feel surprised when the toast vanishes mid-read. Worse, implementations may default to too-short or too-long durations.
CorrectDocument auto-dismiss as a canonical behaviour with a configurable duration property (or a fixed canonical default such as 5 seconds). An optional progress indicator slot may visualise remaining time. Hover-pause is canonical to protect users who are reading.
- 03 Figma
Multiple toast variants for stacking visualisation
CodeA single toast component plus a viewport region that handles stacking
ConsequenceDesigners create "single toast", "two toasts", "three toasts" variants in the design file. Developers ship one toast plus stacking logic; the design file's three-toast variant is decorative, not real, and the production stack behaves differently.
CorrectStacking is a viewport-region concern, not a toast variant. Document the canonical stack-depth maximum and the stacking animation in the viewport's anatomy slot. The toast itself is a single component; the viewport orchestrates.
- 04 Figma
Toast action drawn as link-styled inline text inside body
CodeToast action as a Button in the action slot
ConsequenceDesigners compose body text with inline link "Undo"; the embedded interaction is either a real anchor (wrong semantic — Undo does not navigate) or a span with click handler (no semantic at all). Keyboard reachability and announcement contracts both suffer.
CorrectSingle action lives in the dedicated action slot as a Button element (typically with `variant: tertiary` or `ghost`). The body describes the situation; the action is separately reachable by Tab.