Animated List

A real-time push feed where new items animate in from the top with spring physics — Stripe Radar style.

Installation

File Structure

animated-list.tsx

Usage

import { AnimatedList } from "@/components/unlumen-ui/animated-list";

type Item = { id: number; message: string };

const [items, setItems] = useState<Item[]>([]);

// Prepend new items to show at top:
setItems((prev) => [newItem, ...prev].slice(0, 8));

<AnimatedList
  items={items}
  renderItem={(item) => (
    <div className="rounded-xl border p-3">{item.message}</div>
  )}
/>;

API Reference

AnimatedList

items
T[]

Array of items. Each item must have a unique `id` (string or number). Prepend new items at index 0 for top-push behavior.

renderItem
(item: T, index: number) => React.ReactNode

Render function called for each visible item.

maxVisible?
number
8

Maximum number of items rendered at once. Older items are removed.

gap?
string
"gap-3"

Tailwind gap class applied between items.

className?
string

Extra classes on the list container.

Notes

  • Items must have a stable unique id property (string or number) — this is required for AnimatePresence to correctly track enter/exit animations.
  • Uses AnimatePresence mode="popLayout" so exiting items don't block layout shifts.
  • New items enter with y: -20 → 0 and scale: 0.95 → 1 on a spring; exits use a quick 150ms ease-in.
  • Cap your list with maxVisible to avoid accumulating too many DOM nodes in a live feed.

Keep in mind

Most components on this site are inspired by or recreated from existing work across the web. I'm not here to take credit; just to learn, experiment, and sometimes push things a bit further. If something looks familiar and I forgot to mention you, reach out and I'll fix that right away.