Skip to content
Nizivo UI

Toast

A short message after an action, bottom-centre, with one optional action. toast() shows it from anywhere in your client code; one <Toaster /> in the root layout renders the stack and speaks each message to screen readers.

Tier: own

Import

import { Toaster } from '@nizivo/react/toast';

// Once per app (Getting started), after
// @nizivo/tokens/tokens.css and @nizivo/react/css/base.css and @nizivo/react/css/button.css and @nizivo/react/css/icon-button.css
import '@nizivo/react/css/toast.css';

Static or interactive

Client. <Toaster /> is a client component, and toast() runs in client code: an event handler, an effect, the result of a Server Action read on the client. The server renders nothing for it; the stack and the announcer appear once the page hydrates. Render one <Toaster />, in the root layout, so toasts survive navigation:

// app/layout.tsx
import { Toaster } from '@nizivo/react/toast';

<body>
  {children}
  <Toaster />
</body>;

A page that imports per-component stylesheets needs css/toast.css, css/button.css and css/icon-button.css.

Showing one

import { toast } from '@nizivo/react/toast';

toast('Product saved', { tone: 'success' });
toast('Order #1042 archived', { action: { label: 'Undo', onAction: restore } });
toast('Couldn’t publish 2 products', {
  tone: 'critical',
  description: 'Check the prices and try again.',
});

toast() returns the toast's id. toast.dismiss(id) removes one, toast.dismiss() all of them. Passing an id that is still shown updates that toast in place, for a "Saving…" that becomes "Saved".

tone is neutral (the default), success or critical, Figma's three. The message is one line of plain text; description adds a second.

How long it stays

A toast with no action that is not critical leaves after 5 seconds (timeout changes it). A toast with an action, and a critical one, stays until it is dismissed: someone who needs more time to read it, or to reach the action, must not lose it (WCAG 2.2.1). The time stops while the pointer is over the stack, while focus is in it and while the page is hidden.

Three toasts show at once, newest last (<Toaster limit={…} />). An older one waits, its time stopped, and comes back when one above it leaves.

Screen readers

Each toast is spoken once, when it appears, through the Toaster's announcer: polite, or assertive when critical. The toasts themselves are not live regions, so nothing is read twice. The announcer stays reachable while a Dialog is open, and so does the stack.

announce() speaks through the same announcer, for a status a sighted user sees some other way:

import { announce } from '@nizivo/react/toast';

announce('3 results');
announce('Connection lost', 'assertive');

Over a Dialog

The stack is the one element of the overlay family in the browser's top layer (a manual popover), so it paints above every Dialog, Drawer and popup, and a modal's inert backdrop never covers it. Inside a Dialog, Tab stays in the Dialog; F8 is the way to the stack. Escape on a toast dismisses the toast, not the Dialog.

Focus is never hidden under it

While toasts show, the Toaster writes their height to --nz-toast-inset on <html>, and base.css adds it to scroll-padding-block-end: a control that focus scrolls into view stops above the stack (WCAG 2.4.11). Mobile layouts with a bottom bar set --nz-layout-bottom-inset, which the stack sits above, with the safe area.

Strings

labels={{ region: 'Benachrichtigungen (F8)', dismiss: 'Schließen' }}. The region's name says its shortcut; with hotkey="F9" say F9 in it.

Look

Figma draws the toast dark on a light page (bg/inverse) with a lime action (text/inverse-accent), and light on a dark page. The action is a real tertiary sm Button and the close an IconButton, so both have a 32 px target, a hover and a focus ring; that makes the toast 56 px tall where Figma draws 44 px, which design is asked to confirm. The tone icon is 20 px (Figma: 18, which has no icon token). Hooks: --nz-toast-bg, --nz-toast-radius, --nz-toast-shadow.

Examples

Basic

A confirmation after a save, with one action. toast() runs in an event handler, so this is a client component of your app; <Toaster /> goes once in the root layout.

Source only

It shows toasts from an event handler or an effect, code that runs in a client component of your app, so it is shown as source only.
import { type JSX } from 'react';
import { Button } from '@nizivo/react/button';
import { toast, Toaster } from '@nizivo/react/toast';

export function ToastExample(): JSX.Element {
  return (
    <>
      <Button
        onClick={() =>
          toast('Product saved', {
            tone: 'success',
            action: { label: 'View', onAction: () => {} },
          })
        }
      >
        Save product
      </Button>
      <Toaster />
    </>
  );
}

Stack

Figma's three tones as a stack, newest last. Each has an action or is critical, so all three stay until dismissed; a plain toast would leave after 5 s.

Source only

It shows toasts from an event handler or an effect, code that runs in a client component of your app, so it is shown as source only.
import { useEffect, type JSX } from 'react';
import { toast, Toaster } from '@nizivo/react/toast';

export function ToastStackExample(): JSX.Element {
  useEffect(() => {
    toast('Product saved', { tone: 'success', action: { label: 'View', onAction: () => {} } });
    toast('Couldn’t publish 2 products', {
      tone: 'critical',
      action: { label: 'Retry', onAction: () => {} },
    });
    toast('Order #1042 archived', { action: { label: 'Undo', onAction: () => {} } });
    return () => toast.dismiss();
  }, []);
  return <Toaster />;
}

Props

Shows the toasts toast() adds, bottom-centre, newest last, and speaks each once. F8 moves focus to the stack; Tab moves within it; Escape dismisses the focused toast; F8 again, or Escape on the stack itself, returns focus to where it was. Render one, in the root layout.

Client component Renders no element of its own. Props: ToasterProps. Source: src/toast/toaster.client.tsx.

NameTypeDefaultDescription
classNamestring–
hotkeystring'F8'

The key that moves focus into the stack and, pressed again there, back to where it was (the KeyboardEvent.key value).

labelsPartial<ToasterLabels>–
limitnumber3

Toasts shown at once, newest last. Older ones wait, their time stopped, until one leaves.

Other exports

Politeness type

import type { Politeness } from '@nizivo/react/toast'

How a message is spoken: polite waits for the reader to finish, assertive interrupts.

type Politeness = "polite" | "assertive"

ToastAction type

import type { ToastAction } from '@nizivo/react/toast'

NameTypeDefaultDescription
labelrequiredstring–

The button's text, one or two words: "Undo", "View".

onActionrequired() => void–

Runs on press; the toast then closes.

ToastOptions type

import type { ToastOptions } from '@nizivo/react/toast'

NameTypeDefaultDescription
actionToastAction–

One action, a real button. A toast with an action stays until it is dismissed (WCAG 2.2.1, §12.6), whatever timeout says.

descriptionstring–

A second line under the message.

idstring–

Updates the toast with this id in place, if it is still shown, instead of adding one: toast('Saving…', { id: 'save' }), then toast('Saved', { id: 'save', tone: 'success' }).

onClose() => void–

Called once when the toast leaves, however it left.

timeoutnumber5000

Milliseconds before a toast without an action, and not critical, leaves. The time stops while the pointer is over the stack, while focus is in it and while the page is hidden.

toneToastTone
"neutral""success""critical"
'neutral'
ToastTone type

import type { ToastTone } from '@nizivo/react/toast'

Figma "Tone". Critical is announced assertively and stays until dismissed.

type ToastTone = "neutral" | "success" | "critical"

ToasterLabels type

import type { ToasterLabels } from '@nizivo/react/toast'

Strings the Toaster renders (§16.4).

NameTypeDefaultDescription
dismissrequiredstring'Dismiss'

Each toast's close button.

regionrequiredstring'Notifications (F8)'

The region's accessible name, which names its shortcut.

ToasterProps type

import type { ToasterProps } from '@nizivo/react/toast'

The props of Toaster, listed above.

announce function

import { announce } from '@nizivo/react/toast'

Speaks message through the Toaster's announcer, a live region that is on the page before any message and stays reachable above a modal. For status a sighted user sees some other way: "Saved", "3 results". Needs a mounted <Toaster />.

function announce(message: string, politeness?: Politeness): void

toast constant

import { toast } from '@nizivo/react/toast'

Shows a toast and returns its id. A toast with an action, or a critical one, stays until it is dismissed; any other leaves after timeout (5 s). Every toast is spoken once through the Toaster's announcer: polite, or assertive when critical. Render one <Toaster /> in the app's root layout.

const toast: ((message: string, options?: ToastOptions) => string) & { /** Removes the toast with this id, or every toast. */ dismiss: (id?: string) => void; }

Data attributes and slots

Style parts by class (.nz-<slot>) and state by data attribute. Attribute meanings come from contracts/vocabulary.json.

SlotRendered byData attributes
toast
.nz-toast
Toaster
inner element (CSS only); interactive, focus: self
  • data-nz-scheme: "inverse"
    Inverse surface scheme for the subtree
  • data-tone: "neutral""success""critical"
    The tone prop; values in each component manifest
toast-action
.nz-toast-action
Toaster
inner element (CSS only); interactive, focus: self
none
toast-announcer
.nz-toast-announcer
Toaster
inner element (CSS only)
  • data-nz-top-layer (present or absent)
    Element stays interactive above modal overlays
toast-close
.nz-toast-close
Toaster
inner element (CSS only); interactive, focus: self
none
toast-content
.nz-toast-content
Toaster
inner element (CSS only)
none
toast-description
.nz-toast-description
Toaster
inner element (CSS only)
none
toast-icon
.nz-toast-icon
Toaster
inner element (CSS only)
none
toast-message
.nz-toast-message
Toaster
inner element (CSS only)
none
toast-region
.nz-toast-region
Toaster
inner element (CSS only); interactive, focus: self
  • data-nz-top-layer (present or absent)
    Element stays interactive above modal overlays

CSS hooks

Set a hook on the component's class or any ancestor to restyle it without specificity games; leave it unset for the default shown.

HookDefaultRead as
--nz-toast-bg
  • default: var(--nz-bg-inverse)
  • background on .nz-toast
--nz-toast-radius--nz-radius-lg
  • border-radius on .nz-toast
--nz-toast-shadow--nz-elevation-3
  • box-shadow on .nz-toast

Layers: nz.components. Classes: .nz-button, .nz-icon-button, .nz-toast, .nz-toast-action, .nz-toast-close, .nz-toast-content, .nz-toast-description, .nz-toast-icon, .nz-toast-message, .nz-toast-region. Runtime variables: --nz-layout-bottom-inset.

Tokens this stylesheet reads (26)

--nz-bg-inverse, --nz-distance-lift, --nz-duration-base, --nz-duration-fade, --nz-easing-enter, --nz-elevation-3, --nz-font-body-m, --nz-font-label-m, --nz-font-label-m-strong, --nz-icon-critical, --nz-icon-primary, --nz-icon-success, --nz-radius-lg, --nz-size-control-sm, --nz-size-icon-md, --nz-space-0-5, --nz-space-2, --nz-space-3, --nz-space-4, --nz-space-6, --nz-text-inverse, --nz-text-inverse-accent, --nz-tracking-body-m, --nz-tracking-label-m, --nz-tracking-label-m-strong, --nz-z-toast

Accessibility

These parts are interactive. Each gets the focus outline and touch-action rule from @nizivo/react/css/base.css (the nz.base layer), so the floor survives a restyle:

  • toast: draws the focus outline itself on keyboard focus.
  • toast-action: draws the focus outline itself on keyboard focus.
  • toast-close: draws the focus outline itself on keyboard focus.
  • toast-region: draws the focus outline itself on keyboard focus.

Pattern: WAI-ARIA Authoring Practices.

Keyboard

KeysAction
F8From anywhere on the page, even inside a Dialog, moves focus to the stack of toasts. Pressed again in the stack, returns focus to where it was.
Tab, Shift+TabMoves through the toasts and their action and close buttons.
EscapeOn a toast, dismisses it; focus moves to the next toast, or back to where it was before the stack when none is left. A Dialog under the stack stays open. On the stack itself, returns focus to where it was.
F6The stack is a landmark region named "Notifications (F8)", so F6 (landmark navigation in React Aria apps) and a screen reader's region list reach it too.

Source: Nizivo's own queue and announcer (src/toast/store.ts, toaster.client.tsx), with react-aria 3.53.1 useToastRegion and useToast through _engines/react-aria/toast.client.tsx for the landmark, pausing and where focus goes as toasts leave. F8 and Escape are Nizivo's. Checked by the overlay lane (test/overlay/toast.spec.tsx, O-06, O-07, O-13, O-14) in Chromium, Firefox and WebKit.

Figma

Node ids from design/component-map.json, which nz gen writes from component.json. The links open the Nizivo Figma library, which may ask you to sign in.

On this page