Call toast() from anywhere. One mounted <Toaster/> renders it. Promise-aware, swipe-dismissable, accessible, themeable. Under 5KB, zero runtime dependencies.
live · dogfooded
Every control mutates the same store this page renders from. Change the position, drop the CTAs, watch an upload morph into a result. Swipe one away.
<Toaster position="bottom-right" theme="light" visibleToasts={3} closeButton />
import { toast, Toaster } from "@embertoast/react";
import "@embertoast/react/styles.css";
function Save() {
return (
<button onClick={() => toast.success("Saved")}>
Save
</button>
);
}
// mount once, near the root
export function App() {
return <Toaster position="bottom-right" closeButton />;
}toast() is a store, not a hook. Call it in a handler, a util, or any non-React module. One <Toaster/> renders it.
Promise toasts that morph in place, swipe-to-dismiss, FLIP reflow, pause-on-hover, a depleting timer bar, all on by default.
aria-live done right, never steals focus, honors reduced-motion. Zero deps, under 5KB min+gzip.
React 18+ as a peer. You only install the binding: @embertoast/react.
npm i @embertoast/react
# or
pnpm add @embertoast/react