Toast
Purpose
A Toast is a brief, non-blocking notification that communicates the result of a user action or an important system event. Toasts appear without interrupting the user's current task and dismiss automatically. Use a Toast when: an action has succeeded and the user needs confirmation ("Dataset cloned successfully"), an operation failed and the user should be aware ("Export failed — check your connection"), a background process has completed ("Import finished: 1,240 rows added"), or a time-sensitive system event has occurred ("Your session expires in 5 minutes").
Do NOT use a Toast for: information the user must act on (use a Dialog), persistent warnings that remain relevant beyond 5 seconds (use an inline Alert or Callout), validation errors on form fields (use FieldError inline), or marketing/promotional messages.
Anatomy
A Toast notification is composed of:
- Icon (optional, visually required for semantic variants): a 16x16px icon on the left of the title row. The icon color matches the variant's semantic color. Icon is not interactive.
- Title (required): a short one-line summary of the notification. Rendered in
--force-color-text-primaryat 14px, semibold weight. Should complete within one line (approximately 50 characters maximum). - Header right content (one of three options — mutually exclusive):
- Close button (default): an icon-only
×button that dismisses the toast immediately. Always present unless replaced by a CTA or timestamp. - Timestamp: the time the toast was triggered, formatted as "h:mm a" (e.g., "2:34 PM"). Replaces the close button when a timestamp is provided.
- CTA button: a single tertiary text action (e.g., "Undo", "View details"). Replaces the close button. Use for reversible actions where the user may want to immediately undo the result.
- Close button (default): an icon-only
- Subtitle (optional): a secondary one-line detail beneath the title and icon row. Rendered in
--force-color-text-secondaryat 12px, regular weight. - Description (optional): one or more lines of body text providing additional context. Rendered in
--force-color-text-secondaryat 14px, regular weight. Do NOT use long descriptions — if the notification requires more than two sentences, it belongs in a Dialog or page-level Alert. - Left accent border (optional,
borderedmodifier): a 4px vertical bar on the left edge of the toast, colored to match the variant's semantic color. Usebordered: truewhen the variant's semantic meaning must be reinforced with both an icon AND a border (e.g., in contexts where the icon alone may be missed).
Variants
All variants share the same layout, background (--force-color-bg-surface), and shadow. They differ only in icon color and, when bordered is enabled, left accent border color.
brand (default)
Use for neutral product notifications, informational process completions, and generic system events that are not clearly success, error, warning, or informational in nature. Icon: an info-style icon in the brand indigo color.
success
Use when an action has completed successfully and the user needs confirmation. Examples: "Changes saved," "User invited," "Dataset cloned." Icon: a filled check circle in --force-color-icon-success. Do NOT use success for partial completions or when there are caveats — use warning instead.
error
Use when an action has failed and the user may need to retry or investigate. Examples: "Export failed," "Connection lost," "Permission denied." Icon: a filled warning/alert icon in --force-color-icon-error. Always include a subtitle or description that helps the user understand what went wrong or what to do next.
warning
Use when an action has completed but with a caveat the user should be aware of, or when a proactive system warning is relevant. Examples: "Snapshot completed but 3 files were skipped," "Disk usage at 85%." Icon: an alert icon in --force-color-icon-warning.
info
Use for informational events with no required user action and no negative implication. Examples: "A new version is available," "Maintenance scheduled for tonight." Icon: an info icon in --force-color-icon-info.
States
Appearing (enter animation): Toasts slide in from the bottom of the viewport (or from the corner, depending on the Toaster position). Duration: --force-duration-normal (250ms), --force-easing-decelerate. The toast fades in and translates upward into its resting position.
Visible (resting): The toast is fully rendered and visible at the configured position. Its background is --force-color-bg-surface, it has --force-shadow-lg elevation, and it sits at z-index: --force-z-index-toast (800).
Dismissing (exit animation): The toast fades out and slides away. Duration: --force-duration-normal, --force-easing-accelerate.
Auto-dismiss: By default, toasts dismiss after 5000ms. This timer pauses when the user hovers over the toast (the user is reading it). The timer resumes when the user's cursor leaves the toast.
Hover: The toast remains fully visible (no visual hover effect on the toast itself). The close button (if present) may become more prominent (opacity increases from 0.7 to 1.0). The auto-dismiss timer is paused.
Manual dismiss (close button click): The toast immediately begins its exit animation.
Behavior
- Position: The Toaster is typically positioned at the bottom-right of the viewport in desktop layouts. All active toasts stack vertically above one another, with the most recent at the bottom. The maximum number of simultaneously visible toasts is typically three; additional toasts are queued.
- Width: Fixed at 312px. Do not allow toasts to grow with content width.
- Stacking: Multiple toasts are stacked with a small gap between them. They animate as a group when a new toast is added (existing toasts shift upward).
- Duplicate suppression: If the same toast ID is triggered again while it is still visible, the existing toast is updated in-place rather than creating a duplicate. Use explicit IDs for toasts that represent unique ongoing states.
- Promise pattern: Toasts can be bound to a JavaScript Promise. While the promise is pending, show a loading/info toast ("Importing…"). On resolve, automatically update to success ("Import complete"). On reject, update to error ("Import failed"). This pattern prevents multiple toasts from appearing for the same operation.
- Touch: On touch devices, the user can swipe the toast to dismiss it. The swipe direction should match the toast's exit direction.
Accessibility
- Toasts MUST be announced to screen readers without requiring the user to navigate to them. Render toasts inside a live region container (
aria-live="polite"for most variants,aria-live="assertive"for error toasts that represent critical failures). - Use
aria-live="polite"for success, info, warning, and brand variants. Usearia-live="assertive"sparingly — only when the notification represents an urgent state that should interrupt the user immediately (e.g., session expiry). aria-atomic="true"should be set on the live region so that the entire toast message is announced when it appears, not individual text fragments.- The close button MUST have
aria-label="Dismiss notification"(or similar) since it is icon-only. - The CTA button must have a descriptive label: "Undo" is acceptable; "Click here" is not.
- Auto-dismiss timers should be paused when the user focuses inside the toast (keyboard navigation), not only on mouse hover.
- The Toaster container itself should not receive focus — individual toasts are read by the live region announcement mechanism, not by focus.
- Users who rely on keyboard navigation should be able to reach and interact with toasts via Tab. A common pattern is to include a skip link or ensure the Toaster is in a logical tab order position.
Composition
- A Toast is always rendered by the Toaster component — a singleton mounted once at the application root level. Never create individual toast DOM nodes manually.
- Toasts are triggered programmatically via the
toast()function:toast("Saved", { variant: "success" }). - The
toast.promise()method binds a toast to an async operation (loading → success/error). - The
toast.update()method replaces the content of an existing toast by ID. - Toasts do NOT contain: form fields, navigation links, tables, or complex interactive content. If an action requires more than a single CTA button, use a Dialog instead.
- Do NOT trigger a Toast and a Dialog simultaneously for the same event. Choose one: Dialog if user action is required, Toast if the notification is informational.
- A Toast complements a Dialog by confirming the result after the Dialog has closed (e.g., the Dialog collected the form, the user submitted, the Dialog closes, a success Toast appears).
Guidance
When to choose each variant:
- After a successful form submit, data mutation, or async operation:
success - After a failed operation:
error— include a brief reason and, when possible, a path to resolution - After an operation that succeeded with caveats:
warning - For proactive system information (no action required):
info - For brand-aligned neutral notifications (product updates, feature announcements):
brand
Writing toast messages:
- Title: past tense for completed events ("Dataset cloned"), present tense for ongoing states ("Syncing…"), imperative for advisory ("Check your connection").
- Be specific: "Changes saved to 'prod-clone'" is better than "Saved."
- Subtitle: use for one additional detail (e.g., the number of rows affected, the file name, the time).
- Description: avoid unless necessary — if you find yourself writing three or more sentences, reconsider whether a Toast is the right pattern.
Common mistakes to avoid:
- Do NOT show a Toast for every button click — only for operations that have meaningful async or system-level outcomes.
- Do NOT use the
errorvariant for warnings or informational messages. Semantic color choice must match the actual severity. - Do NOT use a Toast to display a validation error that belongs inline next to the form field.
- Do NOT put more than one CTA button in a Toast. If the situation warrants two actions, open a Dialog.
- Do NOT rely on the Toast as the only form of error feedback — errors in async operations should also be reflected in the originating UI (e.g., the table row's status badge).
Token Usage
Toast container
- Background:
--force-color-bg-surface - Border radius:
--force-radius-card(8px) - Shadow:
--force-shadow-lg - Z-index:
--force-z-index-toast(800) - Width: 312px (fixed)
- Padding:
--force-spacing-3(12px)
Left accent border (bordered: true)
- Width: 4px
- Color (brand):
--force-color-bg-primary(indigo-500) - Color (success):
--force-color-bg-success-subtleaccent → use--force-color-icon-success - Color (error):
--force-color-icon-error - Color (warning):
--force-color-icon-warning - Color (info):
--force-color-icon-info
Icon
- Size: 16x16px
- Color (brand):
--force-color-text-primary-brand(indigo-500) - Color (success):
--force-color-icon-success - Color (error):
--force-color-icon-error - Color (warning):
--force-color-icon-warning - Color (info):
--force-color-icon-info
Title
- Color:
--force-color-text-primary - Font size:
--force-font-size-sm(14px) - Font weight:
--force-font-weight-semibold(600)
Subtitle / Description
- Color:
--force-color-text-secondary - Font size:
--force-font-size-xs(12px)
Timestamp
- Color:
--force-color-text-secondary - Font size:
--force-font-size-xs(12px)
Close button
- Same tokens as
transparent / defaultButton, sm size
Animation
- Duration:
--force-duration-normal(250ms) - Enter easing:
--force-easing-decelerate - Exit easing:
--force-easing-accelerate