Toast

A brief, auto-dismissing notification rendered by the Toaster, fired imperatively with toast().

Usage

Mount one Toaster near the root of the app, then call toast() from anywhere: components, stores, or async handlers.

import { Toaster, toast } from '@epilot/spark-ui/toast'
// once, at the app root
function App() {
  return <Toaster />
}

// anywhere
toast('Settings saved')

Use a toast for brief confirmation of an action that just happened ("saved", "removed", "connected"). For messages tied to a spot on the page, use Callout; for anything the user must read or decide on, use Dialog, because toasts auto-dismiss.

Examples

Types

toast.success / info / warning / error pick the matching icon and tinted surface automatically. Rich colors are on by default; pass richColors={false} for neutral surfaces.

With a description

Secondary text below the title, in muted gray on neutral toasts and the tint color on typed toasts. On a typed toast the icon lines up with the title, not with the block as a whole.

With an action

action renders an accent button on the right edge; its onClick runs and the toast dismisses.

Close button

Every toast gets a close button (top-right) by default. Opt out per toast, or with closeButton={false} on the Toaster.

Promise

toast.promise shows a loading spinner, then swaps to the success or error state when the promise settles.

Position

position belongs to the Toaster, not to a single toast, so every toast in an app stacks in the same corner. Mount one Toaster and pick the corner there.

<Toaster position="top-right" />
ValueStacks from
"bottom-right" (default)bottom edge, upward
"bottom-left", "bottom-center"bottom edge, upward
"top-right", "top-left", "top-center"top edge, downward

Below sm the corner is ignored. The stack goes full-width and anchors to one edge, defaulting to the top because that is what the end-customer portal does, so a block's toasts and the portal's line up. Narrow your browser to see it. Toasts swipe up, down, or right to dismiss.

Use mobilePosition to anchor it to the bottom instead. Full width stays either way; only the edge changes.

// bottom-right on desktop, top of the screen on mobile (default)
<Toaster />

// bottom-right on desktop, bottom of the screen on mobile
<Toaster mobilePosition="bottom" />

This page has one Toaster at bottom-right, which is why the examples above appear there. There is no live switcher: toast() talks to a single module-level manager, so a second Toaster mounted to demo another corner would render every toast twice.

API Reference

Toaster

Mounts the toast region. Built on Base UI Toast, which owns the stacking, timers, swipe-to-dismiss, and the live region.

PropTypeDefaultDescription
position"top-left""bottom-right""bottom-right"Corner the toasts stack in, from sm up
mobilePosition"top" | "bottom""top"Edge the full-width stack anchors to below sm
closeButtonbooleantrueClose button on every toast; a per-toast value wins
richColorsbooleantrueTinted surfaces for success/info/warning/error toasts
durationnumber4000Auto-dismiss time in ms; 0 disables it
limitnumber3Toasts shown at once before older ones collapse behind
classNamestringMerged onto the viewport

toast

toast(message, options?) shows a neutral toast and returns its id. The typed variants pick the icon and tinted surface.

FunctionDescription
toast.success / info / warning / errorTyped toast with matching icon and tinted surface
toast.loading(message)Spinner toast that stays until dismissed or updated by id
toast.promise(p, msgs)Loading, then success or error, driven by the promise
toast.dismiss(id?)Dismiss one toast, or all when called without an id

Common options (second argument):

OptionTypeDescription
descriptionReactNodeSecondary text below the title
action{ label, ...button }Accent pill on the right edge. Beyond label and onClick it takes any <button> prop, so disabled, className, and type pass through
closeButtonbooleanOverride the Toaster's close-button default
durationnumberPer-toast auto-dismiss time in ms
idstringUpdate an existing toast instead of adding one
priority"low" | "high"high announces assertively
onDismiss() => voidRuns when the toast closes

Accessibility

  • Toasts are announced through a live region, so screen readers pick them up without interrupting the current task. Pass priority: 'high' for messages that must interrupt.
  • Timers pause while the pointer is over the region, and F6 moves focus into the notifications landmark.
  • The close and action buttons stay out of the accessibility tree until the region is focused or expanded, so a screen reader does not announce controls for every transient toast.
  • Don't put the only path to an action in a toast (it auto-dismisses); keep a persistent alternative in the page.

On this page