Skip to content

Toast is never shown if called before Toaster subscribes to ToastState #723

Closed

Description

@andreasmcdermott

Toaster component calls ToastState.subscribe in a useEffect (code). If the app calls toast(...) on page load, it might run before the call to subscribe and the toast is never shown.

Example code from our app:

const ToastShownOnPageLoad = () => {
  useEffect(() => {
    if (!shouldShowToast) 

    // This toast will never show up
    const toastId = toast.custom(...);

    return () => {
      toast.dismiss(toastId);
    };
  }, [shouldShowToast]);

  return null;
}

const App = () => {
  return <div>
    <ToastShownOnPageLoad />
    <Toaster />
  </div>
}

A possible workaround is to wrap the call to toast.custom(...) in a setTimeout with 0 delay like so:

const ToastShownOnPageLoad = () => {
  useEffect(() => {
    if (!shouldShowToast) 
    let toastId;

    setTimeout(() => {    
      // This toast will show up
      toastId = toast.custom(...);
    });

    return () => {
      if (toastId)  toast.dismiss(toastId);
    };
  }, [shouldShowToast]);

  return null;
}

const App = () => {
  return <div>
    <ToastShownOnPageLoad />
    <Toaster />
  </div>
}

or alternatively to re-arrange the render order of your components so that Toaster is rendered before ToastShownOnPageLoad (useEffect hooks seem to run in the order the components were rendered, but I haven't confirmed that this is guaranteed):

const ToastShownOnPageLoad = () => {
  useEffect(() => {
    ...
}, [shouldShowToast]);

  return null;
}

const App = () => {
  return <div>
    <Toaster />
    <ToastShownOnPageLoad />
  </div>
}

We can currently work around this issue since we've identified the cause, but it would be nice to not have to worry about the render order!

Reproduction of the issue: https://codesandbox.io/p/sandbox/z8x2mr

Activity

  1. DanielGiljam commented on Dec 19, 2025

    @DanielGiljam

    Yeah, I've run into this issue as well. Would be cool if sonner internally would queue up toast calls until Toaster has mounted and and then flush the queue after Toaster has mounted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions