Animated List — <mv-animated-list>

Animated notification feed: items appear one by one with a spring, smoothly pushing the others (FLIP), with an item limit, loop mode and an add() API.

CategoryData display
TypeWeb Component (<mv-animated-list>)
Statusstable
Keywordslist, notifications, feed, flip, stagger, activity

When to use

Avoid when

Install

node scripts/add.mjs animated-list --out ./src/marvelous

AI agent with the Marvelous UI MCP server: install_components({ slugs: ["animated-list"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).

Files copied (dependencies included): tokens/tokens.css, core/base.css, core/element.js, core/motion.js, core/observe.js, components/animated-list/animated-list.js, components/animated-list/animated-list.css.

Usage

Canonical markup — start from it and customize with attributes, data-* and CSS variables:

<div id="al-demo" style="display:grid;gap:1rem;justify-items:center;width:100%;max-width:26rem">
  <mv-animated-list id="al-demo-feed" interval="1500" max="5" loop fade aria-label="Recent activity" style="width:100%;height:23rem">
    <div class="mv-notification">
      <span class="mv-notification-icon" style="--mv-notification-icon-bg: oklch(0.68 0.16 150)" aria-hidden="true">$</span>
      <div class="mv-notification-body">
        <span class="mv-notification-title">Payment received <small>· Bank</small></span>
        <p class="mv-notification-text">$249.00 from Nebula Studio</p>
      </div>
    </div>
    <div class="mv-notification">
      <span class="mv-notification-icon" style="--mv-notification-icon-bg: oklch(0.62 0.19 265)" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a8 8 0 0 1-11.6 7.1L4 20l1-4.6A8 8 0 1 1 21 12z"/></svg></span>
      <div class="mv-notification-body">
        <span class="mv-notification-title">Sofia Reyes <small>· Messages</small></span>
        <p class="mv-notification-text">“Great, the homepage mockup is approved!”</p>
      </div>
    </div>
    <div class="mv-notification">
      <span class="mv-notification-icon" style="--mv-notification-icon-bg: oklch(0.7 0.17 55)" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m3 17 6-6 4 4 8-8"/><path d="M14 7h7v7"/></svg></span>
      <div class="mv-notification-body">
        <span class="mv-notification-title">Traffic spike <small>· Analytics</small></span>
        <p class="mv-notification-text">+212% visits to the Pricing page</p>
      </div>
    </div>
    <div class="mv-notification">
      <span class="mv-notification-icon" style="--mv-notification-icon-bg: oklch(0.64 0.15 215)" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="8" r="4"/><path d="M4 21a8 8 0 0 1 16 0"/></svg></span>
      <div class="mv-notification-body">
        <span class="mv-notification-title">New sign-up <small>· Team</small></span>
        <p class="mv-notification-text">Daniel Kim joined the Design workspace</p>
      </div>
    </div>
    <div class="mv-notification">
      <span class="mv-notification-icon" style="--mv-notification-icon-bg: oklch(0.6 0.2 330)" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2 4 6v6c0 5 3.4 9 8 10 4.6-1 8-5 8-10V6z"/><path d="m9 12 2 2 4-4"/></svg></span>
      <div class="mv-notification-body">
        <span class="mv-notification-title">Deployment complete <small>· CI/CD</small></span>
        <p class="mv-notification-text">v2.4.0 is live in production · 0 errors</p>
      </div>
    </div>
    <div class="mv-notification">
      <span class="mv-notification-icon" style="--mv-notification-icon-bg: oklch(0.66 0.14 180)" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="17" rx="2"/><path d="M16 2v4M8 2v4M3 10h18"/></svg></span>
      <div class="mv-notification-body">
        <span class="mv-notification-title">Reminder <small>· Calendar</small></span>
        <p class="mv-notification-text">Weekly product sync at 2:30 PM, Lovelace room</p>
      </div>
    </div>
  </mv-animated-list>
  <button class="mv-button" data-variant="outline" data-size="sm" type="button" data-al-add>Send a notification</button>
  <script type="module">
    const root = document.getElementById("al-demo");
    const feed = root.querySelector("mv-animated-list");
    let n = 0;
    root.querySelector("[data-al-add]").addEventListener("click", () => {
      n += 1;
      const card = document.createElement("div");
      card.className = "mv-notification";
      const icon = document.createElement("span");
      icon.className = "mv-notification-icon";
      icon.setAttribute("aria-hidden", "true");
      icon.textContent = "★";
      const body = document.createElement("div");
      body.className = "mv-notification-body";
      const title = document.createElement("span");
      title.className = "mv-notification-title";
      title.textContent = `You have a new fan (${n})`;
      const text = document.createElement("p");
      text.className = "mv-notification-text";
      text.textContent = "Someone added your project to their favorites";
      body.append(title, text);
      card.append(icon, body);
      feed.add(card);
    });
  </script>
</div>

API

Attributes

NameTypeDefaultDescription
intervalnumber1600Delay between two items appearing (ms).
maxnumberMaximum number of items shown; the oldest fade out.
loopbooleanReplays the queue forever (copies of the children) — ideal for demos.
fromtop | bottomtopSide where new items arrive (bottom = chat style).
pausedbooleanPauses the queue.
fadebooleanFades the edge where items exit (--mv-animated-list-fade).

Methods

NameDescription
add(el)Inserts an item immediately, animated. Returns the item.
next()Reveals the next queued item right away.

Events

NameDescription
mv-adddetail.item: the inserted item.

Content structure

NameDescription
childrenInitial queue (revealed in order).

CSS classes

NameDescription
mv-notificationReady-to-use notification card: -icon, -body, -title, -text.

CSS variables

NameDefaultDescription
--mv-animated-list-gapvar(--mv-space-3)Gap between items.
--mv-animated-list-fade5remFade length (with fade).
--mv-notification-icon-bgvar(--mv-accent)Notification icon background.

Accessibility

role=list / listitem. The feed pauses on hover and while focus is inside (time to read), when off-screen and when the tab is hidden. To announce additions, add aria-live="polite" on the element (off by default so screen readers aren’t flooded in loop mode). Reduced motion: items appear without animation.