Noctis

Toast

A transient notification — raised imperatively, announced to assistive tech, and dismissed on a timer, by swipe, or with a button. Toasts stack into a clean peek at the screen corner and fan out on hover, each led by an optional status icon.

Basic

Wrap the tree in a Toast.Provider, render a Toast.Viewport that maps useToast().toasts into Toast.Roots, and raise a toast from anywhere under the provider with the manager. Toast.Content stacks the Title and Description; Toast.Close dismisses it. The provider runs the auto-dismiss timer (5 seconds by default) and announces neutral/info/success/loading toasts politely, while warning/danger toasts use an assertive live region.

Status accents

The typed helpers — info, success, warning, and danger — set the toast's type, which paints any Toast.Icon in the matching status role. The indigo accent is reserved for signal, so a plain show toast carries a neutral icon, not the accent — reach for a status only when the message is genuinely an outcome. A leading icon is the canonical, scannable status cue; map each type to its glyph in your renderer.

Leading icon

Toast.Icon is the optional leading slot — the toast's single chromatic signal. Compose the glyph as its child and it inherits the toast's status colour centrally, so the icon is the one accent, never two. It is decorative (aria-hidden); the title carries the accessible message.

Loading & promise

useToast().promise(p, { loading, success, error }) drives one toast through an async flow: it shows the loading message with Toast.Spinner, then swaps that same toast to the success or error result as the promise settles — never stacking a single flow. The success/error mappers receive the resolved value or the error.

For a flow you settle yourself, loading(title) raises a persistent loading toast (no auto-dismiss); resolve it in place with update(id, …) or close(id). The spinner is neutral and goes static under reduced motion.

Actions & persistence

A toast can carry an inline Toast.Action and a Toast.Close — compose each from a Button through render to inherit the button's look and behaviour. A toast with an action must stay reachable, so pass timeout: 0 to keep it up until acted on (an auto-dismissing toast can vanish before a slow reader reacts). Any caller timeout below the 5-second floor is raised to it.

The canonical destructive pattern pairs the action with Undo: delete optimistically, raise a persistent toast (timeout: 0) whose action restores the item. Base UI fills Toast.Action from the toast's actionProps.

Placement

Toast.Viewport docks via placement (default bottom-end) — a logical corner, so *-start/*-end flip under RTL. Top placements enter from above and stack downward; bottom placements lift off the docked edge. The insets are tokenised through --noctis-toast-viewport-padding.

Anchored toasts

For contextual feedback pinned to a trigger (a transient "Copied" bubble), wrap each toast in Toast.Positioner and pass positionerProps: { anchor } when raising it. The positioner takes over placement (mirroring popup positioning), so the toast leaves the stacked corner and sizes to its content. Keep anchored toasts in their own viewport, separate from the stacked queue.

Custom data

Pass any typed object as data when raising a toast and read it back in the renderer to drive custom content — a mention, a thumbnail, a progress payload. The data rides the toast object Base UI tracks.

Varying heights

Toasts of different heights stack cleanly: Toast.Content clips overflow so the collapsed peek clamps every toast to the frontmost one's height, then each expands to its natural height as the stack fans out on hover or focus.

Deduplicating

Raising a toast with an id that already exists updates it in place and refreshes its timer instead of stacking a duplicate — ideal for a recurring status like “Draft saved”. The toast's updateKey increments on each upsert, so a renderer can replay an attention cue.

The manager

useToast() returns a typed façade over the live queue, callable from any component under Toast.Provider. Like Sheet's useSheetStack, the state is owned upstream (here, Base UI's provider) and reached through context.

  • toasts — the mounted toasts, front to back; map them into Toast.Roots inside the viewport.
  • count — the number of mounted toasts (≈ Sheet's depth).
  • show(options) — raise a neutral toast with the full option set (title, description, timeout, priority, data, …). A caller timeout is floored to 5000ms; pass 0 to keep it up. Returns the toast's id.
  • info / success / warning / danger(title, options?) — raise a status-typed toast; the title is positional. warning/danger announce assertively, the rest politely.
  • loading(title, options?) — raise a persistent loading toast (render Toast.Spinner for it), then settle it with update/close.
  • dismiss(id?) — dismiss a toast by id; omit the id to clear every toast (Base UI closes the whole stack).
  • clear() — clear the whole stack at once (≈ Sheet's reset()); equivalent to dismiss() with no id.
  • update(id, options) — update a live toast in place, refreshing its timer.
  • promise(promise, { loading, success, error }) — drive a single toast through a promise's lifecycle.

Accessibility

  • Politeness follows status. danger and warning are announced assertively (APG alert — they interrupt); info, success, loading, and neutral toasts are polite (status — they wait for idle). The manager maps this for you; for a custom show, set priority: 'high' when the message is urgent.
  • Slow readers come first. Toasts never auto-dismiss faster than 5 seconds, and a toast with an action should set timeout: 0 so it stays reachable. Screen-zoom users can miss a toast entirely — keep critical information off transient surfaces.
  • Focus. F6 moves focus into the viewport and lands on the front toast with a visible ring; focus restores to the page when the last toast closes. Toasts are never tab-trapped.
  • Copy conventions. Write success as {Noun} {past-participle} (“Domain added”), sentence case, no trailing period; end errors with a recovery step. Keep to one tertiary action.

Keyboard

KeyAction
F6Move focus into the toast viewport from anywhere on the page (lands on the front toast).
Tab / Shift + TabMove focus between a focused toast's action and close buttons.
EscWith the viewport focused, dismiss the focused toast.
Enter / SpaceActivate the focused action or close button.

Toasts can also be dismissed by swipe — toward the docked corner (down, or to the end edge, which flips under RTL). Hovering or focusing the stack pauses every auto-dismiss timer and fans the toasts out so each is readable.

Anatomy

Compose a toast from its parts. Toast.Provider owns the queue and the timers (timeout, default 5000ms — 0 disables auto-dismiss; limit, default 3), and Toast.Viewport is the live region that holds the stack.

  • Toast.Provider — hosts the manager and timers, and resolves the translated viewport label. Renders no element of its own.
  • Toast.Viewport — the fixed live region; placement docks it (default bottom-end, data-placement) and data-expanded marks it fanned out.
  • Toast.Root — groups one toast on an elevated Surface. Pass the toast object from useToast().toasts; its type drives the leading status icon's colour (data-type). Swipe-to-dismiss runs toward the docked corner (RTL-resolved).
  • Toast.Content — the card body: a grid of the leading icon, the title/description, and the close button. It holds everything visible, so the collapsed stack can cleanly blank the cards behind the front one (data-behind).
  • Toast.Title + Toast.Description — the accessible name and supporting copy, linked to the root via aria-labelledby and aria-describedby.
  • Toast.Icon — an optional leading status glyph that inherits the toast's colour (decorative).
  • Toast.Spinner — the neutral loading spinner for the loading phase (role="status").
  • Toast.Action — an inline action under the copy; carries the status colour and a focus ring, or composes with a Button through render.
  • Toast.Close — the dismiss button; give it an aria-label, or compose a Button through render.
  • Toast.Portal / Toast.Positioner / Toast.Arrow — for anchored toasts pinned to a trigger.

Every rendered part carries a data-slot (noctis-toast-viewport, noctis-toast, noctis-toast-content, noctis-toast-title, noctis-toast-description, noctis-toast-icon, noctis-toast-spinner, noctis-toast-action, noctis-toast-close) for host-side styling — the root also carries data-type, the viewport data-placement. Pair it with the Base UI state attributes (data-expanded, data-behind, data-limited, data-swiping, data-swipe-direction, data-starting-style, data-ending-style). The root renders through Surface at elevated elevation, so controls inside re-derive off that base and separate cleanly.

Design tokens

Generated from the component's declaration — the same graph that mints the CSS, so a variable name or its resolution default can't drift. The minted tokens are the public override seam: set one on any ancestor and every toast in that region retunes — e.g. .notifications { --noctis-toast-viewport-gap: 0.5rem; } tightens the gap between fanned-out toasts beneath it. Knobs that aren't minted are reached through the part's data-slot. See Customization for the full override ladder and Tokens for the whole graph.

Token

API reference

Generated from the component's types — every prop, type, default, and description comes straight from the source. Each part gets its own table; parts that only forward to Base UI's Toast list just the props they pass through. Expand a row for the full type and description.

Toast.Provider

Prop

Toast.Viewport

Prop

Toast.Root

Prop

Toast.Content

Prop

Toast.Title

Prop

Toast.Description

Prop

Toast.Icon

Prop

Toast.Spinner

Prop

Toast.Action

Prop

Toast.Close

Prop

Toast.Portal

Prop

Toast.Positioner

Prop

Toast.Arrow

Prop

AttributeDescription
data-slotThe styling/testing hook every rendered part carries.
data-typeOn the root: the status type (`info` · `success` · `warning` · `danger` · `loading` · `error`) driving the accent.
data-placementOn the viewport: the docked placement (`bottom-end` · `bottom-center` · `bottom-start` · `top-*`).
data-expandedOn the viewport (and each root/content while it is): present while the stack is fanned out (hover/focus).
data-behindOn the content: present while the toast sits behind the frontmost one in the collapsed stack.
data-limitedOn the root: present when the toast was pushed past the provider's `limit` (kept mounted but inert).
data-swipingOn the root: present while the toast is being swiped to dismiss.
data-swipe-directionOn the root: the physical axis the toast was swiped along (`up` · `down` · `left` · `right`); the default pair is RTL-resolved from the docked corner.
data-starting-styleOn the root: present for the first animation frame after the toast mounts (the enter transition).
data-ending-styleOn the root: present while the toast animates out before it unmounts (the exit transition).