Toast

Briefly confirms an action, then goes away.

Examples

A stack

After a publish

With undo

Kind

  • defaultdefault

  • success

  • warn

  • fail

  • loading

Usage

When to use it
Use
The result of what the person just did is not visible where they are: copied, published.
Use
A background event finished or changed: an index rebuilt, an inbox sync fell behind.
Use
An action can be undone for a short time: archive with Undo.
Not for
The message must stay until its cause is fixed. Use Alert.
Not for
A form field is wrong. Use Field.
Not for
The result is already visible in the view. Use Progress.
Not for
The person must decide before continuing. Use Dialog.

Rules

11 rules
Must
Report a failure with toast.fail, never toast() with fail words. Because a plain toast() times out and waits behind the limit, while toast.fail stays until closed and always shows.
Should
Name what failed and why in a fail toast, and offer the retry as the action.
Must
Leave timeout unset so the reading time applies; pass timeout: 0 only to hold a toast. Because a fixed 3000ms takes the toast away before the person reads it and decides on Undo.
Must
Mount one Toaster at the app root and call toast() from anywhere. Because every Toaster reads the same manager, so two mounted Toasters show each toast twice.
Must
Use toast.promise, or reuse the id with toast.update, when work finishes later. Because toast.loading never times out, so a separate success toast leaves "Rebuilding" on screen beside "Rebuilt".
Should
Write a success title in the past tense with its object under 48 characters: 'Published refund-prompt v14'.
Must
Make a toast's action reachable in the view too, such as Undo in the row menu. Because the toast leaves on its timer, and a keyboard or screen reader user may never reach its button.
Never
Toast after every save; toast only when the result is not visible where the person is. Because a toast for a change already on screen teaches people to ignore the stack, including the fail that matters.
Never
Put an emoji or an exclamation mark in a title. Because a screen reader reads "party popper" before the title, and the title already says what happened.
Should
Keep the Toaster limit at 3 and let the rest wait.
Should
Let a loading toast show its own ring; never add a spinner to its title. Because the toast already leads with a running ring, and a second spinner pushes the title off its edge.

Accessibility

7 checks
The viewport is a region labelled Notifications with aria-live="polite"; F6 moves focus into the stack and pauses timers.
A fail toast has priority high and is repeated in a role="alert" node.
Each toast is a dialog named by its title and described by its description.
Tab moves through action and close; Escape closes the focused toast.
The close button is named Dismiss; the drain line is aria-hidden decoration beside the words.
Hover, focus in the stack and window blur pause the timer and the drain line.
The stack clears the safe area inset; a swipe down or to the end dismisses.

Edge cases

9 edge cases
Long title or 36-character ID
Wraps and breaks; the toast grows and the reading time caps at 12 seconds.
Ten toasts in a second
Three show, the rest wait with timers stopped; a fail never waits.
Empty title
Adds nothing and returns an empty id.
Right to left
The stack sits at the inline end, a swipe toward that edge dismisses, and the drain line shrinks toward the start.
Promise never settles
The loading toast stays until closed.
Reused id
Replaces in place instead of stacking.
Opened from a Dialog
Portals into .quartz and sits above it.
Forced colors
Each toast gets a 1px outline; words carry the kind.
Reduced motion
No rise or fade; the drain line is hidden; the timer still runs.

API

10 props
toast(title, options)
string
options.description
ReactNode
options.action
{label, onClick}
options.timeout
number default reading time
options.id
string default generated
toast.promise(p, {loading, success, fail})
Promise
toast.update(id, kind, title, options)
function
toast.dismiss(id?)
function
readingTimeout(title, description?, hasAction?)
number
Toaster inline, limit, manager
boolean, number, manager default false, 3

Tokens

21 tokens
--surface-page
var(--paper)
--text-1
var(--ink)
--elev-overlay
0 0 0 1px var(--line-frame), 0 12px 24px -12px oklch(var(--text-on-field-c) / var(--shadow-alpha))
--radius-frame
10px
--toast-width
384px
--gutter
24px
--gutter-sm
16px
--warn-text
oklch(49% 0.100 68)
--fail-text
oklch(51% 0.180 26)
--dur-spin
800ms
--type-label
400 14px/16px var(--font-sans)
--type-body-sm
380 13px/18px var(--font-sans)
--text-2
oklch(var(--ink-c) / 0.80)
--text-3
oklch(var(--ink-c) / 0.66)
--dur-base
160ms
--ease-step
cubic-bezier(0.2, 0, 0, 1)
--toast-read-base
3000ms
--toast-read-char
60ms
--toast-read-action
3000ms
--toast-read-min
4000ms
--toast-read-max
12000ms

Install

For your coding agent

GitHub

Please star me pookie

141

A new design system every week

Leave your email before you copy the prompt.