Question presented to candidate:
"Our app shows success and error messages in five different ways. Build us one toast notification system: any component should be able to call something like toast.success('Saved'), toasts stack in a corner, close on their own after a few seconds, and can be closed by hand."
Requirements:
- An app-wide API:
toast(message, options),toast.success,toast.error,toast.info, andtoast.dismiss(id)/toast.dismiss()for all. Each call returns the new toast id. - Toasts stack in a fixed corner, newest first, rendered outside the normal page flow (a portal or equivalent).
- Each toast closes itself after its duration (3 s for success and info, 5 s for errors);
duration: 0makes it sticky. - A close button on every toast; timers are cleaned up when a toast closes early or the app unmounts.
- Accessible: an always-present live region,
role="status"for normal toasts androle="alert"for errors, a labelled close button.
What a strong answer should cover:
- Where the state lives (one list in a provider or service) and why the API object is stable, so callers do not re-render when toasts change.
- Who owns each timer, and the cleanup that stops a removed toast from firing later (and survives React StrictMode).
- Why the stack is rendered at the document body (portal, Teleport, or moving the host element) and positioned with
position: fixed. - Live region rules: the region must exist before content is added;
statusversusalertand when to use each. - Sensible extensions: a max-visible queue, pause on hover, deduplication, promise toasts.
Clarifying questions expected:
- "Should errors stay until dismissed, or close on a timer like the rest?"
- "Is there a limit on how many toasts show at once, or do they stack freely?"
- "Do toasts need to be raised from outside components, for example from an API helper?"
Code / implementation expected: Yes. A provider or service with the toast API, a viewport component, and a toast item with its own timer and close button.