Skip to content
animorio
IT
All components

The stacked notifications

Notifications, Transitions, HoverGSAPAdvancedCompressed weight: Demo 5.4 KBGSAP 28 KBFreeDownload the zip

Notifications come up from below and pile up one behind the other, smaller, showing only their edge; under the pointer the pile opens into a list, and each one leaves by itself, with its cross or dragged away.

The code

A folder that runs on its own: index.html, style.css, script.js and the libraries from a CDN. The React and Vue tabs hold the same demo as a ready component, which switches its animations off when it leaves the page.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>The stacked notifications</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/inter-tight@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the button sends a notification; the notifications pile up at the bottom of the window, the newest in front.
         Under the pointer (or with the focus inside) the pile opens into a list; each one goes by itself after a
         few seconds, or with its cross, or dragged away. The notifications are made by the script -->
    <button class="bell" type="button" data-bell data-autoclic>
      <svg viewBox="0 0 24 24" aria-hidden="true" data-bell-icon><path d="M6 16.5V11a6 6 0 0 1 12 0v5.5l1.5 2h-15zM10 20.5a2 2 0 0 0 4 0"/></svg>
      <span>Show a notification</span>
    </button>
    <!-- a strip of the page's own black along the bottom edge, under the notifications: Safari on iPhone colours the
         band under its bar from a fixed element at the bottom, and without it would take the white notifications -->
    <span class="floor" aria-hidden="true"></span>
    <section class="toasts" aria-label="Notifications" data-toasts>
      <ol class="toasts__list" aria-live="polite" data-list></ol>
    </section>
  </main>

  <script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
  <script src="script.js"></script>
</body>
</html>

Playground

Change values, colours and text with the controls and watch the animation respond live. Or write in the code yourself. Then download the folder with your changes.

33 values to change

Or ask Claude Code for it

With the Animorio connector, Claude Code takes it from here, guide included, and fits it into your project. Paste this request:

Take “The stacked notifications” from Animorio and fit it into my site

What it does

On a black background a light button with a bell, Show a notification. Pressing it, the bell rings swinging and a white notification comes up from the bottom of the window with a little bounce: a coloured icon, a title, a line of text and a cross. The notifications pile up: the newest in front, the older ones behind, each a little smaller and higher, so only their edge shows, up to three. Under the pointer, or with the focus inside, the pile opens into a list and none goes away while it stays open; when the pointer leaves it closes again. Each notification goes by itself after five seconds, or with its cross, or dragged: down, or sideways. On a phone a tap opens and closes the pile. When the page opens a first notification arrives by itself.

How it works

One notification

Each notification is a list item made by the script from one of the MESSAGES: an SVG icon in the message’s colour, the title, a line of text and a cross that says what it closes. They are all the same height (text that does not fit is cut with an ellipsis), so the pile lines up.

The pile and the list

At every change the script works out each one’s place, from the newest: closed, each notification behind goes up PEEK pixels and shrinks by SHRINK, and past VISIBLE it fades; open, each sits above the other with a gap. The new one comes up from below with back.out(SPRING), the others go to their places with power3.out.

Time

Each notification has a GSAP delayedCall that sends it away after LIFE seconds; opening the pile stops all of them and closing it starts them again. Past MAX notifications the oldest goes at once.

Dragging

On pointerdown the notification captures the pointer; after 6 pixels the direction is decided: sideways the notification follows the finger and fades, downwards it goes down (upwards it barely moves). Let go past 90 pixels sideways or 40 down, or thrown quickly, it flies off; otherwise it goes back to its place.

Pointer, keyboard and finger

The pile opens on the mouse’s pointerenter and with the focus inside (focusin), and closes when they leave; open, a pseudo-element keeps the room above the first one, so the pointer can move up among the others without closing it. The list is aria-live polite, so screen readers read the new notifications.

Values to change

NameFileDefaultWhat it changes
LIFEscript.js5The seconds a notification stays.
VISIBLEscript.js3How many notifications show in the closed pile.
PEEKscript.js14How far each one behind peeks out above the one in front, in pixels.
SHRINKscript.js0.055How much smaller each one behind is.
SPRINGscript.js1.4How far a new notification overshoots as it arrives.
MAXscript.js5The most notifications kept at once.
MESSAGESscript.jscinque, da Changes saved a Reminder setThe messages, in turn: the icon, its colour, the title and the line of text.

Try them in the Playground

When to use it

To confirm an action without stopping whoever does it: a save, a sending, an upload, the connection coming back. Short texts, one line of title and one of detail.

On phones

The notifications take the width of the screen minus a margin and sit at the bottom; a tap on the pile opens and closes it, and a finger sends them away by dragging them down or sideways.

With reduced motion

The notifications fade in and out, the pile and the list change at once and the bell does not ring; dragging them away still works.

Pitfalls

  • The notifications behind must be as tall as the one in front, or their edges would peek out at different heights: here they all have the same height and long text is cut with an ellipsis.
  • Open, the list is taller than its container: without the room kept by a pseudo-element, the pointer moving up between two notifications would leave the pile and close it.
  • The drag picks its direction after a few pixels and never changes it: deciding at every move, a slightly crooked finger would make the notification jump between the two directions.
  • A notification’s time stops while it is being touched or the pile is open: otherwise a notification could vanish just as it is being read or dragged.
  • In Safari on iPhone the band under the bottom bar takes its colour from a fixed element near the edge: without a strip of the page’s black under the notifications (the .floor) it would turn white like them.
  • On iPhone two quick taps on the button become a double tap that zooms the page: touch-action: manipulation on the html prevents it.

Libraries

GSAP 3.15.0, Inter Tight (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 5.4 KB; the libraries: GSAP 28 KB.

Testing

Tested on 3 October 2026

  • Desktop: Done
  • Phone: Done
  • Reduced motion: Done
  • Safari on iPhone: Done

License

Use it in your own projects and in your clients’ projects. Do not resell it or redistribute it as is. GSAP stays under its own Standard license. Full license.

All components