Skip to content
Projects

YusufCeng1z/ding has 221 GitHub stars and 5 forks. GitHot measured +70 stars in 24 hours. Last checked 2026-11-09 18:44 UTC. Last push 2026-11-06.

How these counts are measured

Toasts with real spring physics. One toast that morphs in place. No dependencies. React, Svelte and plain DOM.

221 stars5 forks +70 in 24h

Measured star growth

in 24h
+70
in 7 days
Collecting history
in 15 days
Collecting history
in 1 month
Collecting history

Net star changes over overlapping periods, not daily totals. Missing measurements are left blank. Stars measure attention, not software quality.

README.md

Original

Ding mascot

Ding

Toasts with real spring physics.
One toast that morphs in place. No dependencies. React, Svelte or plain DOM.

Live demo and docs

A progress toast turns into a success toast, then an error toast with a Retry button morphs into a new message


Why Ding

  • One toast at a time. A new call morphs the toast on screen instead of stacking a second one.
  • Real springs. Size, shape and text move on a spring solver, so interrupting an animation keeps its momentum.
  • No stylesheet. Styles are injected from JavaScript. Nothing to import.
  • Light, dark and system themes, six positions, right-to-left support.
  • Rich content. Description, avatar, buttons, progress bar, a countdown line, small trailing text.
  • Accessible by default. Persistent live regions, keyboard dismiss, prefers-reduced-motion.
  • Optional sound. A soft built-in tone per status, or plug in your own.
  • Strict TypeScript, ESM and CommonJS builds.

Install

npm i @yusufceng1z/ding-react    # React 18+
npm i @yusufceng1z/ding-svelte   # Svelte 5
npm i @yusufceng1z/ding          # plain DOM

Each framework package depends on the small @yusufceng1z/ding core, so you install only one.

Quick start

Render the toaster once, then call toast from anywhere.

React

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

export default function App() {
  return (
    <>
      <Toaster position="top-center" theme="system" />
      <button onClick={() => toast.success('Saved')}>Save</button>
    </>
  );
}

Svelte 5

<script>
  import { Toaster, toast } from '@yusufceng1z/ding-svelte';
</script>

<Toaster position="top-center" theme="system" />
<button onclick={() => toast.success('Saved')}>Save</button>

Plain DOM

import { mountToaster, toast } from '@yusufceng1z/ding';

mountToaster({ position: 'top-center' });
toast.success('Saved');

Usage

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

Every call returns the toast id.

Promises and updates

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

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.

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

Options

Option Description
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
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. Hover and keyboard focus pause the timer. Repeating the same toast adds a counter (×2).

Configure

toast.configure({
  position: 'bottom-right', // top-left, top-center, top-right, bottom-left, bottom-center, bottom-right
  theme: 'dark',            // system, light, dark
  sound: true,
  volume: 0.5,
});

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

Sound

Off by default. With sound: true each status plays 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. Browsers keep audio locked until a click or key press.

To use your own sounds, pass a function. It receives success, error, warning, info or loading:

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

Accessibility

  • Messages go through persistent live regions: errors are assertive, everything else is polite.
  • Esc dismisses. Alt + T moves focus into the toast.
  • Respects prefers-reduced-motion.
  • Mirrors automatically on right-to-left pages.

Packages

Package Description
@yusufceng1z/ding Springs, timers, store, sound and the plain DOM renderer
@yusufceng1z/ding-react React renderer
@yusufceng1z/ding-svelte Svelte 5 renderer

The core owns all behavior. The framework packages only render.

Development

pnpm install
pnpm test        # unit tests
pnpm typecheck
pnpm build       # build all packages
pnpm dev         # docs and demo site

The docs site lives in apps/docs. A machine-readable summary is in apps/docs/public/llms.txt.

License

MIT

Explore related projects