npm · no framework · shadow DOM

Toast notifications, delivered by Pip.

Pip pulls the card in from the nearest edge, parks it in a toaster dock, then comes back and pushes it out when it dismisses. Weight comes from content length — short copy is a sprint, a wall of text is a struggle.

npm install pip-toaster

Edge in, edge out

Six docks. Left and right, Pip walks beside the card. Top and bottom center, Pip flanks it so the character stays on screen.

Weight is the copy

Length picks the gait: sprint, walk, lean-and-slip, or two Pips on a vertical toast. You don’t configure the animation — the text does.

Host CSS can’t leak

Styles are injected into a Shadow DOM overlay. No framework, no stylesheet import. Call toast() from anywhere in the browser.

Try it here

These buttons call the real library. Watch Pip enter from the dock you pick below.

Install

ESM + generated .d.ts. Source is TypeScript; tsc is the only build step. Safe on the server: createToaster is a no-op when document is missing.

# npm
npm install pip-toaster

# or
pnpm add pip-toaster

Usage

import { toast } from "pip-toaster";

toast("Meeting in 10 minutes.");

toast.success("Saved.");
toast.warning({
  title: "Queue lag",
  message: "Workers are retrying.",
});

API

One singleton for most apps. Reach for createToaster when you need a second stack, a custom mount, or a localized close label.

toast(input)

toast(input: string | ToastPayload): string

Shows a toast and returns its id. A string is treated as message. Empty payloads (no title, message, content, or action) are ignored and return "".

toast({
  title: "Sprint review",
  message: "Bring your notes.",
  position: "bottom-right",
  duration: 5000, // ms; 0 = sticky until ×
});

const id = toast("Queued.");
toast.dismiss(id);
toast.dismissAll();

ToastPayload

Field Type Notes
title string Card heading.
message string Main copy. body and description are aliases.
content ToastContent Extra nodes. Prefer a factory if the node has listeners — the card is rebuilt for delivery, parking, and dismiss.
action ToastAction | ToastAction[] Footer buttons. dismiss defaults to true. variant is primary or ghost.
status ToastStatus default · info · success · warning · error. Pip’s shirt and the card accent follow this.
position ToastPosition Overrides the toaster default for this toast only.
duration number Milliseconds. 0 stays until dismissed — Pip reads beside the card.

Shortcuts

toast.info · toast.success · toast.warning · toast.error

Same as toast({ …, status }). A string argument becomes the message.

toast.error({
  title: "Deploy failed",
  message: "The worker ran out of memory.",
  action: [
    { label: "Retry", onClick: () => {} },
    { label: "Details", variant: "ghost", dismiss: false },
  ],
});

toast.configure(options)

configure(options: { position?, duration?, zIndex?, card? }): void

Defaults for the singleton. Call before the first toast, or later to change dock, timing, stacking order, or card colors.

toast.configure({
  position: "top-right",
  duration: 4000,
  card: {
    background: "#111827",
    color: "#f9fafb",
    accent: "#e07a5f",
  },
});

accent is the default-status highlight. info / success / warning / error keep their own accent. Pip’s shirt still follows status; hat and skin stay as they are.

Custom content

Unstyled button / a inside content pick up the toast styles. Pass a factory so listeners survive the carry animation.

toast({
  title: "File deleted",
  content: (ctx) => {
    const undo = document.createElement("button");
    undo.textContent = "Undo";
    undo.addEventListener("click", () => ctx.dismiss());
    return undo;
  },
});

createToaster(options)

createToaster(options?: ToasterOptions): Toaster

Isolated instance. Use it for a second stack, a custom mount node (position: relative), or a localized close label. If target is omitted, the overlay is position: fixed on document.body.

import { createToaster } from "pip-toaster";

const notify = createToaster({
  position: "bottom-left",
  duration: 5000,
  target: document.querySelector("#app"),
  labels: { close: "Dismiss" },
});

notify("Hello");
notify.destroy();
Option Default Notes
position bottom-right Default dock for toasts that omit position.
duration 5000 Milliseconds. 0 is sticky.
zIndex 2147483000 Overlay stacking.
target document.body Custom mount. Overlay becomes absolute.
labels Dismiss Close button aria-label. Not shown on the card.
card background, color, accent.

Positions

Click a cell — the next toast (and the live ones on this page) use that dock. Heavy vertical toasts get two Pips.

Status

Shirt color and card accent track status.

default info success warning error

Effort

classifyEffort(title, message) maps trimmed character count to a gait. You rarely need this — Pip already uses it.

light ≤ 42 characters. Sprint. One hand.
normal ≤ 118. Steady walk.
heavy ≤ 260. Lean, slips, both hands. Two Pips on top/bottom.
massive 261+. A real struggle. Exhausted pause before the drop.