Skip to content
API reference

toast()

Create toasts from anywhere — event handlers, tasks, plain modules. The store is global, so no context or hook is needed; the <Toaster /> picks them up.

toast(message, options?)          // neutral toast
toast.message(message, options?)  // alias of toast()
toast.success(message, options?)
toast.info(message, options?)
toast.warning(message, options?)
toast.error(message, options?)
toast.loading(message, options?)  // spinner, never auto-closes
toast.promise(promise, data)      // loading → success / error
toast.custom((id) => jsx, options?)
toast.dismiss(id?)                // one toast, or all of them
toast.getToasts()                 // active toasts
toast.getHistory()                // created so far (up to 100)

message is a string, JSX, or a function returning either. Every helper takes the same options object as its last argument.

Types

toast("Event has been created");

toast("Event has been created", {
  description: "Monday, January 3rd at 6:00pm",
});

toast.success("Event has been created");
toast.info("Be at the area 10 minutes before the event time");
toast.warning("Event start time cannot be earlier than 8am");
toast.error("Event has not been created");
toast.loading("Creating event…");

toast.loading() has no timer: update it (see below) or dismiss it when the work is done.

Action and cancel

Add a primary action and/or a secondary cancel button. Handlers are QRLs. The toast closes after the click unless the action sets preventDefault: true — Qwik's take on sonner's event.preventDefault().

import { $ } from "@qwik.dev/core";

toast("Event has been created", {
  action: {
    label: "Undo",
    onClick$: $(() => toast.success("Change reverted")),
    // preventDefault: true, // keep the toast open after the click
  },
  cancel: {
    label: "Cancel",
    onClick$: $(() => console.log("Cancelled")),
  },
});

Instead of an Action object you can pass any JSX as action or cancel; it renders as-is.

Promise

toast.promise() shows a loading toast and turns it into a success or error toast when the promise settles. Pass a promise, or a function / QRL returning one.

import { $ } from "@qwik.dev/core";

const createEvent = $(
  () => new Promise<{ name: string }>((resolve) =>
    setTimeout(() => resolve({ name: "Sonner" }), 2000),
  ),
);

const result = toast.promise(createEvent, {
  loading: "Creating event…",
  success: $((data: { name: string }) => `${data.name} has been created`),
  error: "Could not create the event",
  finally: $(() => console.log("settled")),
});

// Await the original value (or rejection) after the toast updates.
const data = await result.unwrap();
FieldTypeDefault
loadingstring | JSXOutput—
Message of the loading toast. Without it no toast is shown until the promise settles.
successstring | JSXOutput | QRL<(data) => …> | ExtendedResult—
Shown when the promise resolves. Functions receive the resolved value and may return a message or { message, ...options }.
errorstring | JSXOutput | QRL<(error) => …> | ExtendedResult—
Shown when the promise rejects, resolves to an Error, or resolves to a Response with ok: false (the function then receives HTTP error! status: <code>).
descriptionstring | JSXOutput | QRL<(data) => …>—
Description for the settled toast. A plain value is also shown while loading; a function runs once settled.
finallyQRL<() => void | Promise<void>>—
Runs after the promise settles, whatever the outcome.
…optionsExternalToast—
Any toast option (except description, above) — applied to the loading toast.

Changing options on settle

Return an object with a message to change the settled toast's options too:

toast.promise(save, {
  loading: "Saving…",
  // Return { message, ...options } to also change the toast's options.
  success: $((data: Doc) => ({
    message: "Saved",
    description: `${data.title} is up to date`,
    action: { label: "View", onClick$: $(() => open(data.url)) },
  })),
  error: $((err: Error) => err.message),
});

Custom JSX

Pass JSX as the message to keep the default look, or use toast.custom() to render only your own markup — it drops the default toast styles but keeps stacking, swiping and timers.

// JSX as the message keeps the default toast styling
toast(<span>Signed in as <strong>diecodev</strong></span>);

// toast.custom renders only your markup; the callback receives the id
toast.custom(
  (id) => (
    <div class="my-toast">
      <strong>You've unlocked Pro</strong>
      <button onClick$={() => toast.dismiss(id)}>Dismiss</button>
    </div>
  ),
  { duration: Number.POSITIVE_INFINITY },
);

Updating a toast

Call any helper with the id of an existing toast to update it in place.

const id = toast.loading("Uploading…");

// Same id → the toast updates in place, keeping its position in the stack
toast.success("Upload complete", { id });

Dismissing

const id = toast("Event has been created");

toast.dismiss(id); // remove one toast
toast.dismiss();   // remove every toast

Use onDismiss$ and onAutoClose$ to react to a toast closing — see callbacks.

Reading state

toast.getToasts();  // toasts currently on screen (not dismissed)
toast.getHistory(); // toasts created so far, dismissed ones included (up to 100)

For a reactive list inside a component use useSonner().

Return values

CallTypeDefault
toast(), .success(), …string | number—
The toast id — the one you passed as id, or an auto-incremented number.
toast.custom()string | number—
The toast id; also passed to your render callback.
toast.promise()(string | number) & { unwrap }—
The id with an unwrap() method that resolves/rejects like the original promise. Without loading only { unwrap } is returned; without a second argument, undefined.
toast.dismiss()string | number | undefined—
The id you passed, if any.