SolutionsPackagesComponentsCLI — Coming soonResourcesDocumentationStorybookChangelogBlogAboutSign up freeGet early access

Documentation

Toast

Live-region notifications triggered from anywhere with toast(), shown in a queued, pausable stack by one dsgn-toaster.

Open this component in Storybook

Toasts are short notifications announced to assistive technology without taking focus. Mount one <dsgn-toaster> per app, then call toast() from anywhere. The toaster is the only stateful piece. toast() just dispatches a dsgn-toast event on document.

Usage

<dsgn-toaster
  label="Notifications"
  dismiss-label="Dismiss notification"
  queued-label="+{count} queued"
  paused-label="paused"
></dsgn-toaster>
import '@ds-gn/ui/toaster';
import { toast } from '@ds-gn/ui/toast';

toast.success('Changes saved', {
  description: 'Token overrides were published.',
});
const id = toast.error('Couldn’t publish', {
  description: 'The registry rejected the request.',
  actions: [{ label: 'Retry', onClick: retry }],
});
toast.dismiss(id); // or toast.dismiss() for every toast

@ds-gn/ui/toast does not import Lit, so it is safe to import during a server render, where calls are no-ops. In the browser, calls made before a toaster connects are held (up to 20) and shown in order once one does.

In React, mount the wrapper once and call toast(). No provider or hook is needed:

import { Toaster, toast } from '@ds-gn/ui/react';

<Toaster label="Notifications" dismissLabel="Dismiss notification" />;
toast.info('Sync started');

Playground

Props

PropTypeDefaultDescription
max-visiblenumber3maxVisible. Timed toasts shown at once before the rest queue. Persistent toasts don’t count.
labelstring''Accessible name for the region, e.g. “Notifications”.
dismiss-labelstring''dismissLabel. Accessible name for each dismiss button. Required for an accessible button.
queued-labelstring''queuedLabel. Pill text while toasts wait; {count} is replaced. Empty shows just “+N”.
paused-labelstring''pausedLabel. Added to the pill while timers are paused.
surface'light' | 'dark''light'Semantic token surface to use.

Toast options

interface ToastOptions {
  title: string;
  description?: string; // newlines start a new line
  variant?: 'info' | 'success' | 'warning' | 'error'; // default 'info'
  duration?: number; // ms; 0 persists. Defaults: 5000, 5000, 7000, 0 (error)
  actions?: {
    label: string;
    onClick?(): void;
    appearance?: 'primary' | 'secondary';
  }[]; // up to 2
  links?: {
    label: string;
    href?: string;
    target?: '_blank' | '_self'; // with href; '_blank' adds rel="noopener"
    onClick?(): void;
  }[];
  icon?: string; // a registered icon name in place of the variant's
  onDismiss?(reason: 'timeout' | 'close' | 'action' | 'programmatic'): void;
}

The toast helpers are toast(options), toast.info | success | warning | error(title, options?), which return the toast’s id, and toast.dismiss(id?).

Slots

This component has no slots.

CSS parts

PartDescription
regionThe labelled notification region.
queueThe “+N queued” pill.
listThe stack of toasts.
toastEach toast’s surface.
iconA toast’s variant icon.
titleA toast’s title.
descriptionA toast’s description.
linksA toast’s row of links.
actionsA toast’s row of actions.
actionEach action button.
dismissThe dismiss button.
progressThe time-remaining bar.

Events

EventDetailDescription
dsgn-dismiss{ id, reason }Fired when a toast is dismissed. reason is timeout, close, action or programmatic. React: onDsgnDismiss.

Methods

MethodDescription
show(options)Show a toast on this toaster and return its id.
dismiss(id?)Dismiss one toast, or every toast (shown and queued).

Behaviour

  • Queue. Up to max-visible timed toasts show at once. More wait first in, first out, and their timers don’t start until they show. Errors and any duration: 0 toast skip the queue and don’t count toward the limit, so a pile of errors can never stall it.
  • Pause. Hovering or focusing anywhere in the region pauses every timer, fans the collapsed stack out, and greys the progress bars.
  • Top layer. The region is a popover="manual" element fixed to the bottom-end corner. A modal dialog makes everything outside it inert, so while a <dsgn-modal> is open the region moves into it and stays reachable. Other native modal dialogs are not handled.

Accessibility

  • Both live regions, role="status" (polite) and role="alert" (assertive, errors only), exist as soon as the toaster connects. A toast is announced as “Title. Description.” when it becomes visible, not when it is queued.
  • Toasts never take focus. Dismissing the focused toast moves focus to the next toast’s dismiss button, or to the region, never to <body>.
  • Dismiss and action buttons are 32px but get a 44px hit area on touch screens.
  • Motion runs through @ds-gn/motion; under prefers-reduced-motion: reduce toasts fade without moving and the stack jumps into place.
© 2026 LightLeap Labs LLC. All rights reserved. · Terms of Service · Privacy Policy · Cookies · Contact · Support