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.
Toasts with real spring physics. One toast that morphs in place. No dependencies. React, Svelte and plain DOM.
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
Toasts with real spring physics.
One toast that morphs in place. No dependencies. React, Svelte or plain DOM.
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.
Escdismisses.Alt+Tmoves 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
Explore related projects
ytdl-org/youtube-dl
Command-line program to download videos from YouTube.com and other video sites
141,500 starsexcalidraw/excalidraw
Virtual whiteboard for sketching hand-drawn like diagrams
135,396 starsgodotengine/godot
Godot Engine – Multi-platform 2D and 3D game engine
119,840 starsmrdoob/three.js
JavaScript 3D Library.
117,983 stars