Docs

Press Run on any example to see the real toast. Prefer plain text? llms.txt

Install

There is no stylesheet to import: styles are injected from JavaScript.

npm i @yusufceng1z/ding-react

Using shadcn/ui? This installs the package and adds a ding-toaster.tsx wrapper:

npx shadcn@latest add @ding/ding
npm i @yusufceng1z/ding-svelte
npm i @yusufceng1z/ding

Setup

Render the toaster once, near the root of your app.

import { Toaster } from '@yusufceng1z/ding-react';

export default function App() {
  return (
    <>
      <Toaster position="top-center" theme="system" />
      {/* your app */}
    </>
  );
}
<script>
  import { Toaster } from '@yusufceng1z/ding-svelte';
</script>

<Toaster position="top-center" theme="system" />
import { mountToaster } from '@yusufceng1z/ding';

const unmount = mountToaster({ position: 'top-center' });

Show a toast

Import toast from the same package and call it from anywhere. Every call returns the toast id. toast.loading(title) works the same and stays until you update or dismiss it.

import { toast } from '@yusufceng1z/ding-react@yusufceng1z/ding-svelte@yusufceng1z/ding';

toast.success('Saved');
toast.error('Payment failed', { description: 'Card declined' });
toast.warning('Storage almost full');
toast.info('New version available');

Only one toast is visible at a time. A new call morphs the toast on screen instead of stacking a second one. Repeating the same toast adds a counter (×2).

Update in place

Wrap a promise and one toast moves from loading to the result:

toast.promise(save(), {
  loading: 'Saving…',
  success: 'Saved',
  error: (err) => `Could not save: ${err.message}`,
});

Or update by hand, for progress and other long jobs:

const id = toast.loading('Uploading photo…', { progress: 0 });
toast.update(id, { progress: 0.6 });
toast.update(id, { type: 'success', title: 'Photo uploaded', progress: null });

Only the newest caller can update the shared toast, so a slow request that finishes late cannot overwrite a newer message.

Actions

An onClick may return a patch. The toast then morphs in place instead of closing. A returned patch removes the buttons unless it names them again.

toast.success('Message deleted', {
  action: {
    label: 'Undo',
    onClick: () => {
      restore();
      return { type: 'info', title: 'Restored' };
    },
  },
});

Options

description
Second line of text.
action
{ label, onClick }. The main button.
secondary
{ label, onClick }. A quieter button beside the action.
image
Avatar or thumbnail URL. Replaces the status icon.
meta
Small trailing text, such as “now” or “⌘V”.
progress
0 to 1. Draws a thin bar at the bottom of the toast.
duration
Milliseconds before it closes. 0 keeps it until dismissed. Default 5000.
id
Reuse an id so repeated calls from one place stay one caller.

Errors, loading toasts and toasts with a button stay until dismissed, so nobody misses something they need to act on. Hover and keyboard focus pause the timer.

Configure

toast.configure({
  position: 'bottom-right', // top-left, top-center, top-right, bottom-left, bottom-center, bottom-right
  theme: 'dark',            // system, light, dark
  labels: { dismiss: 'Fermer la notification' }, // screen reader names, English by default
  sound: true,
  volume: 0.5,
});

toast.dismiss(id);  // one toast
toast.dismiss();    // all

Position, theme and labels can also be set as props on the toaster. The toast follows reading direction, so right-to-left pages mirror automatically.

labels sets the names screen readers announce for the notifications region (region) and the close button (dismiss). Keys you leave out keep their English default, so a non-English page only needs to translate what it uses.

Sound

Off by default. Turn it on and each status gets its own soft tone: success rises, error falls, warning double-taps, info is a single note. Loading is silent, and progress updates never make a sound.

toast.configure({ sound: true, volume: 0.5 });

Browsers keep audio locked until a click or key press, so the first sound has to follow one. To use your own sounds or a sound library, pass a function. It receives success, error, warning, info or loading, once per new toast and once per status change.

toast.configure({ sound: (type) => mySounds.play(type) });

Accessibility

  • Messages go through persistent live regions: errors are announced assertively, everything else politely.
  • Esc dismisses. Alt + T moves focus into the toast.
  • Respects prefers-reduced-motion.
  • Buttons stay out of the tab order until the toast has opened.