You Might Also Like
Recent Purchase Notification Popup — Free HTML CSS JS FOMO Toast Snippet
Recent Purchase Notification Popup · Modals · Plain HTML, CSS & JS · Live preview
What's included
Features
About this UI Snippet
Recent Purchase Notification Popup — HTML, CSS & JavaScript FOMO Toast

A "recent purchase" or "FOMO" notification is the small toast — popularized by tools like Fomo and Proof — that periodically appears in the corner of an e-commerce site showing something like "Jordan D. in New York just bought Wireless Headphones." It's a lightweight social-proof signal that other real people are actively buying, meant to nudge hesitant visitors.
This snippet implements the full cycling behavior in plain HTML, CSS, and vanilla JavaScript, with no third-party social-proof service.
How the notification queue works
A plain array, NOTIFICATIONS, holds a handful of { initials, name, location, product, time } objects. An index variable tracks which one is currently showing, and renderNotification fills the toast's avatar initials, message text, and timestamp from whichever entry is at that index. (index + 1) % NOTIFICATIONS.length advances to the next entry and wraps back to the start once the list is exhausted — so the cycle repeats indefinitely.
How the slide-in/out animation works
The toast sits fixed at bottom: 24px; left: 24px with transform: translateX(-120%) by default — fully off-screen to the left. Adding the .visible class animates it to translateX(0) using a spring-like cubic-bezier(0.22, 1, 0.36, 1) easing curve, which gives a slight overshoot-and-settle feel rather than a plain linear slide.
How the show → wait → hide → cycle loop works
Two named timing constants drive the whole loop: VISIBLE_DURATION (how long each toast stays on screen before auto-hiding) and GAP_BETWEEN (how long the toast stays completely off-screen before the next one appears). showToast() displays the current notification and schedules hideToast() after VISIBLE_DURATION. hideToast() removes the .visible class, advances the index, and schedules the next showToast() after GAP_BETWEEN. Because each function schedules the other via setTimeout, the cycle runs indefinitely without a setInterval, which is important — a fixed interval would fire even while a previous toast's exit animation was still playing, whereas this chained-timeout approach always waits for the current toast's full cycle to finish first.
Manual dismissal
Clicking the × button calls hideToast(true), which behaves identically to the automatic timeout except it schedules the *next* notification slightly further out (GAP_BETWEEN * 1.5) — a small courtesy so a visitor who explicitly closed a toast isn't immediately shown another one.
Accessibility
The toast has role="status" and aria-live="polite", so screen readers announce each new notification's text as it appears, without interrupting whatever the user is currently doing.
Build with AI
Build, Understand, Optimize, and Extend It With AI
Give this snippet's HTML, CSS, and JS to an AI coding assistant like Claude and ask it to explain why alternating setTimeout calls between the show and hide functions avoids the overlap and timing-drift problems a single repeating setInterval would introduce for this kind of cyclic toast animation. It's also worth discussing the ethics and legal considerations of this pattern with the assistant — ask it to help you design a version that only ever displays genuine, real-time purchase events pulled from your actual order system, since presenting fabricated activity as real social proof can be misleading to users and is restricted under consumer protection regulations in several jurisdictions.
Prompt to recreate it
Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:
Build a "recent purchase" social-proof toast notification that periodically cycles through a list of items in plain HTML, CSS, and JavaScript — no third-party social-proof service or script.
Requirements:
- A toast fixed near a bottom corner of the viewport, hidden off-screen by default via a CSS transform, that slides into view with a spring-like eased transition when shown.
- A data-driven notification queue (a plain array of objects with fields like name, location, product, and a relative timestamp) that the toast renders from, with a single render function that updates the toast's content from whichever entry is currently active.
- Implement the show/wait/hide/cycle loop using chained setTimeout calls between a show function and a hide function — not a single repeating setInterval — so that each phase only begins once the previous one has actually completed, and the cycle wraps back to the first entry after the last one.
- Include a close button that lets the user dismiss the current toast immediately, which should also cause the next notification in the cycle to wait somewhat longer than usual before appearing, as a courtesy.
- Give the toast container role="status" and aria-live="polite" so each new notification is announced to screen reader users without interrupting their current task or stealing keyboard focus.
- Keep all timing values (how long a toast stays visible, how long the gap between toasts is) as clearly named constants near the top of the script so they are easy to tune.Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.
Step by step
How to Use
- 1Load the snippetClick "Recent Purchase Notification Popup" in the sidebar Library tab. After about 1.5 seconds, the first toast slides in from the bottom-left.
- 2Watch it cycleLet it run — the toast auto-dismisses after a few seconds, pauses briefly, then shows the next entry from the notification list, looping indefinitely.
- 3Dismiss one manuallyClick the × to close a toast early and notice the next one waits slightly longer before appearing.
- 4Edit the notification listIn the JS panel, edit the NOTIFICATIONS array to reflect real (or realistic) purchases relevant to your store.
- 5Tune the timingAdjust VISIBLE_DURATION and GAP_BETWEEN in the JS panel to control how long each toast stays visible and how long the gap is between them.
- 6Connect to real order dataReplace the static NOTIFICATIONS array with data fetched from your order/checkout backend for genuine (not fabricated) recent activity.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
Not by default — the demo uses a hardcoded array of example notifications. For a legitimate use, replace the array with data fetched from your real order or checkout system rather than fabricating purchases, which can mislead users and run afoul of consumer protection rules in some jurisdictions.
setInterval fires on a fixed schedule regardless of what else is happening, which could trigger the next show while the current toast's hide animation is still playing. Each function here calls setTimeout to schedule the next step only once its own logic has run, keeping the cycle strictly sequential and glitch-free.
Edit the VISIBLE_DURATION constant in the JS panel — it is the number of milliseconds a toast stays on screen before it automatically hides and the cycle advances to the next notification.
Edit the GAP_BETWEEN constant — it is the number of milliseconds the toast stays fully hidden before the next one slides in. Dismissing a toast manually adds a 50% longer pause as a courtesy before the next one appears.
Yes. Replace the NOTIFICATIONS array with data from a WebSocket connection, Server-Sent Events stream, or periodic API poll against your order system, pushing new entries into the array (or a queue) as real purchases happen.
Yes. The toast container has role="status" and aria-live="polite", so assistive technology announces each new notification's text as it appears, without stealing focus or interrupting the user's current task.
Yes. Change left: 24px to right: 24px on .fomo-toast, and flip the initial transform to translateX(120%) so it slides in from the opposite direction.
No — dismissing a toast early just hides it sooner and slightly delays the next one; the cycle continues indefinitely afterward. If you want dismissal to stop the whole feature for a session, you could set a sessionStorage flag inside the close handler and check it before scheduling future notifications.