Skip to content
Getting started

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@beta

Quick start

Render the Toaster once, in your root layout, then call toast() from any component.

src/routes/layout.tsx
import { component$, Slot } from "@qwik.dev/core";
import { Toaster } from "qwik-sonner";

export default component$(() => {
  return (
    <>
      <Toaster />
      <Slot />
    </>
  );
});
src/routes/index.tsx
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:

sonner (React)
qwik-sonner
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.

Next steps