Toast

Brief feedback after an action, at the edge of the window.

StableSince 1.0.0
On this page

Import

import { ToastProvider, useToast } from '@envsemble/envui';

Usage

Put one ToastProvider near the root of the application. Any component inside it calls useToast(), whose show shows a notification and returns its id, dismiss(id) dismisses one, and clear() dismisses them all. show takes the message, a short sentence that wraps to three lines, its tone, an action, a placement, dismissible and a duration.

SaveChanges.tsx
import { useState } from 'react';
import { Button, ToastProvider, useToast } from '@envsemble/envui';

function SaveButton() {
  const toast = useToast();
  const [saving, setSaving] = useState(false);
  const save = () => {
    setSaving(true);
    // Saving takes a moment; a timer stands in for it here.
    window.setTimeout(() => {
      setSaving(false);
      toast.show({ tone: 'success', message: 'Changes saved.' });
    }, 1200);
  };
  return (
    <Button pending={saving} onClick={save}>
      Save changes
    </Button>
  );
}

export default function SaveChanges() {
  // An application puts one ToastProvider near its root.
  return (
    <ToastProvider>
      <SaveButton />
    </ToastProvider>
  );
}

Tones

tone is neutral, the default, with no icon, success, info or danger. Every tone takes the same dark fill, and the tone shows in its icon, so a stack stays quiet beside the page's content. A danger notification stays until it is dismissed, is announced at once as an alert, and is never hidden behind the count.

A toast has no warning tone, unlike Alert: a warning needs attention where it applies, so it is an Alert on the page, not a notification that passes.

toast.show({ tone: 'danger', message: 'Changes couldn’t be saved.' });

Actions and duration

action is one button, with its label and its onClick; the notification stays until it is dismissed, so call dismiss with the id show returned once the action has run.

  • duration is how long it stays, in milliseconds: 5000 by default, or Infinity for danger notifications and those with an action.
  • It counts only while the notification is visible, pauses on hover and keyboard focus, and starts again in full when it returns from behind the count or from behind a modal.
  • Infinity or 0 keeps it until it is dismissed, and a negative number throws a RangeError.
  • dismissible={false} leaves out the dismiss button; it still closes after its duration, with Esc while focused and with dismiss.
const id = toast.show({
  message: `${name} archived.`,
  action: {
    label: 'Undo',
    onClick: () => {
      restore(name);
      // The action doesn't close the notification by itself.
      toast.dismiss(id);
    },
  },
});

Placement and limit

ToastProvider's defaultPlacement is bottom-end, stacking upward from the bottom corner at the end of the line in the text direction, or top-center; placement on one notification overrides it. limit, 3 by default, is how many each placement shows at once.

<ToastProvider defaultPlacement="top-center" limit={2}>
  <App />
</ToastProvider>

Composition

The parts are each placement's region, env-toast-viewport, with data-placement; each notification, env-toast, with data-tone; its tone icon and message together, env-toast-content, the tone icon, env-toast-status-icon, its message, env-toast-message, its action, env-toast-action, and its dismiss button, env-toast-dismiss; the count of hidden notifications, env-toast-queued-count; and the announcements, env-toast-announcer. The region names, the hidden count and the dismiss button's name come from the provider's messages.

Customize

A Toast draws an edge only at high contrast, unless its outline color sets one, and its container color takes the place of the dark fill; with its content color set, the tone icon takes that color too.

Accessibility

You provide

  • One ToastProvider around the components that call useToast.
  • A message that makes sense read on its own.
  • dismiss(id) once an action has run.

envUI provides

  • A named region per placement, and a polite announcement of each notification.
  • A danger notification as an alert, announced at once and never hidden behind the count.
  • Timers that pause on hover, on focus and while the window is in the background.
  • Fades only, under reduced motion.

Props

ToastProvider

Hosts the notifications that useToast shows: brief feedback at the edge of the window, announced and dismissed after a few seconds or by people. Put one near the root of the application; it renders a region for each placement in a portal, in the theme of the place it is rendered.

PropTypeDescription
childrenrequired
ReactNode
The application, or the part of it whose components call useToast.
defaultPlacementDefault 'bottom-end'
'bottom-end''top-center'
Where notifications show unless show names a placement: bottom-end, stacking upward from the bottom corner at the end of the line, or top-center, stacking downward from the top.
limitDefault 3
number
How many notifications each placement shows at once, a positive integer. The newest stay visible; older ones wait behind a count of hidden notifications and come back as newer ones close. Danger notifications always show, and take their places first.

useToast

Shows and dismisses notifications through the nearest ToastProvider: show, dismiss and clear. Throws outside a provider.

useToast(): ToastManager

Part names

Each part's class and state attributes are public and versioned, for an application's CSS to style.

env-toast
One notification.
env-toast-action
A notification's action.
env-toast-announcer
The announcements of notifications.
env-toast-content
A notification's tone icon and message, side by side, the icon level with the message's first line.
env-toast-dismiss
A notification's dismiss button.
env-toast-message
A notification's message.
env-toast-queued-count
The count of notifications waiting.
env-toast-status-icon
The icon of a notification's tone.
env-toast-theme
The theme boundary around the notifications.
env-toast-viewport
The region that holds the notifications.
data-ending-style
Present
data-leaving
Any value, or present
data-limited
Present
data-placement
bottom-end · top-center on env-toast-viewport
data-settling
Any value, or present on env-toast-viewport
data-starting-style
Present
data-toast-id
Any value, or present on env-toast, env-toast-queued-count
data-tone
danger · info · neutral · success

Color properties

Each sets a color of one instance, through style or CSS; its hover, focus and press follow it. They are public and versioned.

--env-toast-container
The fill, in place of the tone; set, the dismiss button's states are state layers over it.
--env-toast-content
The message, icons and dismiss button, and the color of its state layers.
--env-toast-outline
The edge.

Strings

EnvUIProvider's messages overrides each, and a component's own label prop wins over it.

messages.toast.regionBottomEnd
"Notifications" Names the notifications at the bottom end: the right, or the left in right-to-left text.
messages.toast.regionTopCenter
"Top notifications" Names the notifications at the top center.
messages.toast.hidden
({ count, countText }) => string The count of notifications waiting behind the shown ones; `countText` is the count in the locale's digits.
messages.toast.dismiss
"Dismiss notification" A notification's dismiss button.

Changelog

1.0.0

No edge outside high contrast, where the tone's edge bounds it, and an alert's corners, 1.25 rem. The notifications' theme boundary, env-toast-portal-theme, is env-toast-theme, as Popup's is env-popup-theme.

limit for visibleLimit, as Base UI names it. tone for variant, with danger for error, and ToastTone; bottom-end for bottom-right, which follows the text direction, with the top-center stack centered in either direction; the region names, hidden count and dismiss button come from the provider's messages; danger notifications are alerts at once and always shown; the dismiss button is an IconButton with a cross; the manual Toast is gone.

ToastProvider and useToast keep their names. The manual Toast component and ToastProps are no longer exported; show notifications with useToast inside ToastProvider.

1.0.0-prerelease.6

A toast fades in with --env-motion-ease-enter, so it shows from its first frames rather than late, while it arrives from its edge as before.

Notifications glide and a revealed one fades in with the motion tokens, --env-motion-duration-slow and --env-motion-duration-medium with --env-motion-ease-enter, so durations of 0s stop them.

The tone icon stands on its own, without its disc, at a control's icon size, 20 px, and level with the message's first line, beside which a message of two or three lines starts; the icon and the message sit together in env-toast-content.

Every tone takes the neutral toast's dark fill, --env-color-bg-neutral-strong, with its icon in the tone's light grade on a faint disc of it, rather than a solid green, blue or red fill. Every toast in a region is one width, 22 rem, less the gutters on a phone, so a stack's edges line up.

A toast takes the large corner of the radius scale, --env-radius-lg, as an alert does, rather than a fixed 1.25 rem.

The action is an outline button in the notification's own text color, with its edge in that color and the dismiss button's hover and press fills, rather than a blue primary button on the tone's fill. Notifications wait while a modal is open in the same container and show once it closes, rather than covering its actions.

1.0.0-prerelease.5

16 px from its start edge to its icon or message, and 10 px between its parts.