Introduction
An opinionated toast component for Qwik. A resumable port of sonner by Emil Kowalski: render one <Toaster />, call toast() from anywhere, ship zero hydration.
Every button on these pages fires a real toast.
Installation
Version 2 targets Qwik 2: @qwik.dev/core 2.0.0-rc.4 or later. While it's a pre-release it's published under the beta dist-tag, so name the tag explicitly:
npm install qwik-sonner@betaQuick start
Render the Toaster once, in your root layout, then call toast() from any component.
import { component$, Slot } from "@qwik.dev/core";
import { Toaster } from "qwik-sonner";
export default component$(() => {
return (
<>
<Toaster />
<Slot />
</>
);
});import { component$ } from "@qwik.dev/core";
import { toast } from "qwik-sonner";
export default component$(() => {
return (
<button onClick$={() => toast("My first toast")}>
Give me a toast
</button>
);
});Styled or headless
The default entry injects sonner's stylesheet. qwik-sonner/headless renders the exact same markup and data-sonner-* attributes without any CSS, for when you want to own the look entirely.
// Styled (default) — ships sonner's stylesheet via useStyles$
import { Toaster, toast } from "qwik-sonner";
// Headless — same API and markup, no styles
import { Toaster, toast } from "qwik-sonner/headless";Differences from sonner
The API mirrors sonner as closely as Qwik's resumability allows. What changes is how functions cross the server/client boundary:
onClick: () => …onClick$: $(() => …)onDismiss / onAutoCloseonDismiss$ / onAutoClose$event.preventDefault()action.preventDefault: trueclassName / classNamesclass / classesRe-render with new propsposition={signal}Callbacks stored on a toast must be QRLs — wrap them in $(). Toaster props that should change after the page loaded (position, theme, richColors, dir, invert) accept a Signal.