npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@editora/toast

v2.1.1

Published

Enterprise toast notification library for React and web apps, with SaaS-ready UX patterns, accessibility, and high-performance lifecycle controls.

Readme

Features

  • Nothing to mount. No provider, no container element: the first call creates what it needs. It works from React, Vue, plain JavaScript, a service, or an event handler.
  • A modern card. An opaque, neutral surface with a status icon (a different shape for each level, so colour is never the only cue), in light and dark. Dark follows the system, or your app's own .dark switch.
  • A stack that opens on hover. Several toasts fold into a deck, the newest in full; hover it or focus it and it opens into a list while the timers wait.
  • Promise toasts. One toast follows a promise from loading to success or error.
  • Actions and progress: buttons in the toast, and a progress bar with an optional percentage.
  • Thirteen themes and seven positions, a queue (three toasts show at once by default), duplicate prevention and swipe-to-dismiss.
  • Keyboard and screen readers. Alt+T jumps to the toasts, Escape dismisses one, errors are announced as alerts and the rest politely, and prefers-reduced-motion is respected.
  • Small. 15 KB gzipped plus 5 KB of CSS. No dependencies.
  • Safe on the server. The package imports in Node and the calls do nothing there, so a call in shared code does not break server rendering.
  • Written in TypeScript. A script tag works too (a UMD build).

Install

npm install @editora/toast

Quick start

import { toast } from '@editora/toast';
import '@editora/toast/toast.css';

toast.success('Document saved');
toast.info('A new version is available');
toast.warning('Storage is almost full');
toast.error('Upload failed');

Toasts appear in the bottom-right corner and go away after four seconds. Three are visible at once; the rest wait in a queue (a fourth toast, Upload failed above, appears when there is room). With more than one toast showing they fold into a deck: see Stacking.

toast is all you need. Call it with a message for a plain toast, or use toast.info, toast.success, toast.warning, toast.error and toast.loading, each taking a message and, if you like, an options object or a duration in milliseconds. toast.show, toast.promise, toast.update, toast.dismiss, toast.clear and toast.configure cover the rest. toastAdvanced (also exported as toastPro) is the same plus groups, plugins and subscriptions.

Titles, actions and progress

import { toast } from '@editora/toast';
import '@editora/toast/toast.css';

// A toast with a title, a description, actions and progress. duration: 0 keeps it until it is dismissed.
const report = toast.show({
  level: 'success',
  title: 'Report ready',
  description: 'Q3-summary.pdf is 2.4 MB',
  actions: [
    { label: 'Open', primary: true, onClick: () => console.log('open') },
    { label: 'Dismiss', onClick: () => report.dismiss() }
  ],
  duration: 0
});

const upload = toast.show({
  level: 'info',
  message: 'Uploading photos',
  progress: { value: 64, showPercentage: true },
  duration: 0
});

show() returns the toast: dismiss() removes it and update(options) changes it. Pressing an action runs its onClick and closes the toast; give the action dismissOnClick: false to keep the toast open. The progress bar follows update(id, { progress }).

Promises and updates

toast.promise() shows one toast that becomes the result of a promise, and update() changes any toast by id:

import { toast } from '@editora/toast';
import '@editora/toast/toast.css';

const saveDocument = new Promise<{ name: string }>((resolve) => {
  setTimeout(() => resolve({ name: 'Q3-summary.pdf' }), 1500);
});

// One toast that moves from loading to success or error by itself.
toast.promise(saveDocument, {
  loading: 'Saving document...',
  success: (file) => `Saved ${file.name}`,
  error: (error) => `Could not save: ${error.message}`
});

// Or update a toast yourself.
const sync = toast.loading('Syncing...');
setTimeout(() => {
  toast.update(sync.id, { message: 'Everything is up to date', level: 'success' });
}, 2500);

toast.promise() returns the promise you gave it, so you can still await it. If you only need the message, success and error can be plain strings; they can also be options ({ title, description, actions }), which replace the loading text.

Stacking

import { toast } from '@editora/toast';
import '@editora/toast/toast.css';

// By default several toasts fold into a deck: the newest in full, the others as edges behind it.
// Hover the deck (or press Alt+T) and it opens into a list; the timers wait while it is open.
toast.success('Document saved');
toast.info('A new version is available');
toast.warning('Storage is almost full');

// Prefer a plain list that is always open?
// toast.configure({ stack: false });

The newest toast is always the one nearest the edge of the screen. While the deck is open, the timers of its toasts wait, and a toast that arrives meanwhile waits with them. A toast that is dismissed leaves at once and the others close the gap. stack: false keeps a plain list; stack: true, expand: true shows a list that is always open.

On a touch screen a tap opens the deck; a tap elsewhere closes it.

Icons

import { toast } from '@editora/toast';
import '@editora/toast/toast.css';

// A list instead of a deck, so all four are visible at once.
toast.configure({ maxVisible: 4, stack: false });

toast.success('Saved');                              // the icon of the level
toast('Copied to clipboard');                        // no level, no icon
toast.info('Invite sent', { icon: '✉️' });           // your own: text, an emoji or a DOM node
toast.error('Payment failed', { icon: false });      // none

// Or switch the built-in icons off everywhere:
// toast.configure({ icons: false });

The built-in icons are drawn in SVG from the level's colour (--et-success, --et-error, ...) and are hidden from screen readers; the message carries the meaning. icon takes a string (text or an emoji), a DOM node, or false.

In React, and in any framework

There is nothing to render. Call toast from a handler, an effect or a service:

import { toast } from '@editora/toast';
import '@editora/toast/toast.css';

async function saveDraft() {
  await new Promise((resolve) => setTimeout(resolve, 800));
  return { name: 'draft.md' };
}

// There is nothing to mount: call toast from any handler or effect.
export default function SaveButton() {
  return (
    <button
      onClick={() =>
        toast.promise(saveDraft(), {
          loading: 'Saving...',
          success: (file) => `Saved ${file.name}`,
          error: 'Could not save'
        })
      }
    >
      Save
    </button>
  );
}

@editora/ui-react also has a ToastProvider and a useToast() hook if you like a provider.

From a script tag

The UMD build defines three globals: toast, toastAdvanced and toastPro (the same object as toastAdvanced). Pin a version in production, as here:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@editora/toast@2/dist/toast.css" />
<script src="https://cdn.jsdelivr.net/npm/@editora/toast@2/dist/index.umd.js"></script>

<button id="save">Save</button>

<script>
  document.getElementById('save').onclick = () => {
    // The script defines three globals: toast, toastAdvanced and toastPro (the same object as toastAdvanced).
    toast.success('Saved from a CDN');

    const notification = toastAdvanced.show({
      message: 'File uploaded',
      level: 'success',
      actions: [
        { label: 'View', onClick: () => console.log('view') },
        { label: 'Dismiss', onClick: () => notification.dismiss() }
      ],
      duration: 0
    });
  };
</script>

Configure it

configure() sets the defaults for every toast from then on. A single toast can still override them:

import { toast } from '@editora/toast';
import '@editora/toast/toast.css';

// Settings for every toast from now on. A toast can still override them.
toast.configure({
  position: 'top-center',
  duration: 6000,
  maxVisible: 3,
  theme: 'ocean',
  closeButton: true,
  preventDuplicate: true
});

toast.info('Welcome back');
toast.info('Welcome back'); // the duplicate is dropped
toast.warning('Your plan renews tomorrow', { theme: 'sunset', duration: 0 });

| Setting | Default | | | --- | --- | --- | | position | 'bottom-right' | Where toasts appear (see Positions). | | duration | 4000 | How long a toast stays, in milliseconds. 0 keeps it until it is dismissed. | | maxVisible | 3 | How many show at once; the others wait in the queue. (visibleToasts is an alias.) | | queueStrategy | 'fifo' | 'fifo' or 'lifo': which waiting toast comes next. | | theme | 'system' | One of the themes. | | closeButton | false | Show a close button on every toast. | | icons | true | Show the built-in status icons. | | preventDuplicate | false | Drop a toast whose content is already showing. With dedupeScope: 'visible', 'queue' or 'all' (the default). | | stack, expand, gap | true, false, 8 | A deck that opens on hover (stack), a list that is always open (expand, or stack: false), and the gap between toasts. | | pauseOnHover, pauseOnFocus, pauseOnWindowBlur | true, true, false | Hold the timers while the pointer is over the stack, a toast has keyboard focus, or the window is in the background. The time that was left is kept. | | hotkey | 'alt+t' | A shortcut that moves focus to the toasts, for example 'ctrl+shift+k'; false turns it off. | | swipeDismiss, swipeDirection, dragDismiss | true, 'any', false | Dismiss by swiping, in which direction, and by dragging. | | offset, mobileOffset, zIndex | 16, 16, none | The distance from the edge of the screen, on desktop and on mobile, and the stacking order. | | rtl | false | Right-to-left layout. | | richColors | false | Tint each toast with the colour of its level. | | container | the page body | The element toasts are added to. |

toast.getConfig() (on toastAdvanced) returns the current settings.

Themes

light, dark, system, colored, minimal, glass, neon, retro, ocean, forest, sunset, midnight and custom. Set one for all toasts with configure({ theme }), or for one toast with { theme }:

import { toast } from '@editora/toast';
import '@editora/toast/toast.css';

// A deck would fold these into one; stack: false keeps them in a list.
toast.configure({ position: 'top-right', maxVisible: 12, stack: false, gap: 8 });

const themes = [
  'light', 'dark', 'colored', 'minimal', 'glass', 'neon', 'retro', 'ocean', 'forest', 'sunset', 'midnight'
] as const;

for (const theme of themes) {
  toast.info(`The ${theme} theme`, { theme, duration: 0 });
}

The picture at the top of this page is that code. system (the default) follows the operating system's light or dark setting, and your app's own switch: a dark class, or data-theme="dark", data-bs-theme="dark", data-color-scheme="dark" or data-mantine-color-scheme="dark" on the <html> element (and light for an app that is light while the system is dark). Each toast carries data-theme and level classes (editora-toast-info, ...).

A theme is a set of CSS variables, so you can make your own with a few lines (the custom theme leaves the colours to you):

.editora-toast[data-theme="custom"] {
  --et-bg: #fffbeb;
  --et-text: #292524;
  --et-text-muted: #78716c;
  --et-border: #fcd34d;
  --et-success: #15803d; /* the colour of the success icon; also --et-error, --et-warning, --et-info, --et-loading */
  --et-radius: 16px;
}

--et-width, --et-font, --et-shadow, --et-action-bg and --et-action-ink (the primary button) are variables too.

Positions

top-left, top-center, top-right, bottom-left, bottom-center, bottom-right and center:

import { toast } from '@editora/toast';
import '@editora/toast/toast.css';

toast.configure({ maxVisible: 10 });

const positions = [
  'top-left', 'top-center', 'top-right',
  'bottom-left', 'bottom-center', 'bottom-right',
  'center'
] as const;

for (const position of positions) {
  toast.success(position, { position, duration: 0 });
}

Toast options

Everything show() accepts. All of it is optional except a message (or a title):

| Option | | | --- | --- | | message, title, description | The text. | | level | 'info', 'success', 'warning', 'error' or 'loading'. | | icon | Your own icon: a string (text or an emoji) or a DOM node; false for none. Left out, the level's icon. | | actions, action, cancel | Buttons: { label, onClick, primary?, dismissOnClick? }. | | progress | { value, showPercentage? }, with value from 0 to 100. | | duration, persistent | How long it stays (0, or persistent: true, keeps it until dismissed). | | position, theme, customClass, rtl | Where it appears and how it looks. | | closable / closeButton | Show a close button. | | html | Render message as HTML. Only inline formatting, lists and safe links are kept. | | render | Build the toast yourself: (toast) => HTMLElement. | | priority, important | Show higher priorities first; important also pushes lower-priority toasts out. | | preventDuplicate, dedupeKey, dedupeScope | Drop duplicates, by content or by your own key. | | pauseOnHover, pauseOnFocus, swipeDismiss, swipeDirection, dragDismiss | Behaviour; see the settings. | | role, ariaLive | Override the announcement (see Accessibility). | | group | The id of a group the toast belongs to. | | animation | Animation settings (a CSS animation by default; spring and other types are available). | | onShow, onHide, onUpdate | Lifecycle callbacks. |

Accessibility

Toasts live in a region that is announced politely. An error toast is a role="alert" with aria-live="assertive", so a screen reader interrupts to read it; every other level is role="status" with aria-live="polite". The close button is labelled "Close notification", and the icons are decorative (a different shape for each level, so a toast is not told apart by colour alone). Override the announcement of one toast with role and ariaLive.

Keyboard. Every toast is a Tab stop, so its buttons can be reached before it goes away. Alt+T (hotkey) moves focus to the newest toast and opens the stack; Escape dismisses the focused toast and moves on to the next one, or back to where you were. While a toast has keyboard focus, or the pointer is over the stack, the timers wait. With prefers-reduced-motion the toasts fade instead of sliding.

API

toast:

| Method | | | --- | --- | | toast(message, options?) | A plain toast, with no level and no icon. | | info, success, warning, error, loading (message, options?) | A toast of that level. | | show(options) | Show a toast from full options; returns { id, options, dismiss(), update(options) }. | | promise(promise, { loading, success, error }) | A toast that follows a promise (also onSuccess and onError); resolves with the promise's value. | | update(id, options) | Change a toast. | | dismiss(id?) / clear() | Remove one toast, or (with no id) every toast. | | configure(settings) | Set the settings. |

toastAdvanced (toastPro) has all of those and more:

| Method | | | --- | --- | | group(id, options) | Show a toast that belongs to a group. | | getConfig() | Read the settings. | | getToasts() / getGroups() / getState() | The toasts, the groups, or both with the queue and the settings. | | subscribe(listener) | Call listener(state) when the toasts change; returns an unsubscribe function. | | use(plugin) | Install a plugin: { name, install(manager), uninstall? }. | | onEditorEvent(event, callback) / triggerEditorEvent(event, toast, ...args) | Connect toasts to your editor's events. | | destroy() | Remove every toast and the toast region. |

The classes and types are exported too: ToastManager, and ToastOptions, ToastConfig, ToastInstance, ToastPosition, ToastTheme, ToastPromiseOptions and more. If you are upgrading from 1.x, see the migration guide.

Upgrading from 2.0

2.1 changes how toasts look and where they sit; nothing was removed.

  • The look. The card is opaque and neutral, with a status icon, instead of a see-through tint with a coloured stripe (the page showed through the text). The dark theme is dark (it was a white card), and the primary button is readable in dark mode. richColors gives the tinted card back. configure({ icons: false }) removes the icons.
  • Stacking. Several toasts fold into a deck by default, and the newest toast is nearest the edge of the screen (it used to be farthest). To get a plain list: configure({ stack: false }).
  • Timers. Hovering or focusing the stack holds every toast and keeps the time that was left; before, each toast was held on its own and started again from the full duration.
  • Keyboard. Toasts are Tab stops, Alt+T and Escape work, and pauseOnFocus is on. configure({ hotkey: false }) turns the shortcut off.
  • The simple API gained toast(message), promise, update, dismiss, clear, configure and show.
  • Browsers. The layout uses the individual translate and scale properties: Chrome 104, Safari 14.1, Firefox 72 or later.
  • If you styled toasts with CSS, the accent stripe (::before) and the tinted background of the level classes are gone: set --et-* variables or --et-accent, or restyle .editora-toast.

Part of Editora

@editora/ui-react depends on this package.

License

MIT © Ajay Kumar