Skip to the solution
MediumFrontend12 min read

Build a Toast / Snackbar Queue with Pause on Hover

601 views

The problem

Question presented to candidate: "Our toasts pile up when a sync job fails twenty times in a row. Build a toast queue: at most three on screen, the rest wait their turn, each closes after three seconds with a progress bar, and hovering a toast pauses it. When the mouse leaves, it should continue from where it was, not start again."

Requirements:

  • A toast API (success, error, info, dismiss) available app-wide.
  • At most 3 visible toasts; the rest wait in FIFO order, with a "+N more" indicator.
  • When a visible toast closes (timer or close button), the next queued one appears, and its 3 s timer starts only then.
  • Hovering or keyboard-focusing a toast pauses its timer; leaving resumes with the remaining time, not the full duration.
  • A progress bar that stops while paused; role="alert" for errors, role="status" otherwise, inside a live region.

What a strong answer should cover:

  • One array in arrival order as the source of truth, with "visible" and "waiting" derived from it rather than stored separately.
  • The pause and resume maths: record when the timer started, subtract the elapsed time on pause, schedule the remainder on resume.
  • Starting each timer when the toast becomes visible, not when it is queued.
  • Pausing on focus as well as hover (keyboard users, WCAG timing), and not double-subtracting when both happen.
  • Clean timer teardown on close and unmount, and how to test with fake timers.

Clarifying questions expected:

  • "Does hovering one toast pause just that one, or the whole stack?"
  • "Should errors jump the queue, or stay in arrival order?"
  • "What happens when the tab is in the background: keep counting or pause?"

Code / implementation expected: Yes. A queue provider or service, a toast item with a pausable timer, and a stack that renders the first three plus a waiting count.

  • React
  • Toast
  • Queue
  • Animation

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

12 min read ยท 10 sections

React solution

Every file of the working solution. Open it in the playground to run and change it.

ReactComplete solution
import { useRef } from "react";
import {
  ToastQueueProvider,
  useToast,
  MAX_VISIBLE,
  DURATION,
} from "./src/components/ToastQueue";

function Demo() {
  const toast = useToast();
  const count = useRef(0);
  const next = () => ++count.current;
  return (
    <main className="demo">
      <h1>Toast queue</h1>
      <p>
        At most {MAX_VISIBLE} toasts show at once; the rest wait in line. Each
        closes after {DURATION / 1000} s. Hover or focus a toast to pause its
        timer.
      </p>
      <div className="buttons">
        <button
          data-testid="btn-success"
          onClick={() => toast.success("Saved item " + next())}
        >
          Success
        </button>
        <button
          data-testid="btn-error"
          onClick={() => toast.error("Sync failed " + next())}
        >
          Error
        </button>
        <button
          data-testid="btn-burst"
          onClick={() => {
            for (let i = 0; i < 5; i++) toast.info("Notification " + next());
          }}
        >
          Burst of 5
        </button>
      </div>
    </main>
  );
}

export default function App() {
  return (
    <ToastQueueProvider>
      <Demo />
    </ToastQueueProvider>
  );
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 53 of 107 in Machine coding

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

Up nextMedium

Build an Analog Clock

Continue