A list whose items slide and fade in one after another, and stack as new ones are added. It is a real list (ul with li items), and every item is in the page from the start.
Optional, and kept apart.
Nothing here is included in a project unless you add it, and the plain component it builds on is unchanged. This effect is decoration: it is hidden from screen readers, stands still for visitors who prefer reduced motion, and can be paused. Use Still on a preview to see that version.
- Payment received
- Invoice sent to Dana
- Stock reserved
- Courier booked
import { AnimatedList } from "@rdloom/react";
const steps = ["Payment received", "Invoice sent to Dana", "Stock reserved", "Courier booked"];
export default function AnimatedListBasicExample() {
return (
<div className="flex w-full justify-center">
<AnimatedList className="w-full max-w-sm">
{steps.map((step) => (
<div
key={step}
className="rounded-[var(--rd-radius-control)] border border-[var(--rd-color-border-default)] bg-[var(--rd-color-surface-raised)] px-4 py-3 text-sm text-[var(--rd-color-text-default)]"
>
{step}
</div>
))}
</AnimatedList>
</div>
);
}Installation
npx rdloom add animated-listCopies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes.
It also adds rdloom-motion.css next to your tokens and imports it from the tokens file, once: no setup, and no inline styles. The plain components you already use are untouched.
Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/animated-list.jsonWorks, but without upgrade tracking, and you import the motion CSS yourself.
Usage
import { AnimatedList } from "@rdloom/react";
<div className="flex w-full justify-center">
<AnimatedList className="w-full max-w-sm">
{steps.map((step) => (
<div
key={step}
className="rounded-[var(--rd-radius-control)] border border-[var(--rd-color-border-default)] bg-[var(--rd-color-surface-raised)] px-4 py-3 text-sm text-[var(--rd-color-text-default)]"
>
{step}
</div>
))}
</AnimatedList>
</div>Live feed
- Order 1042 shipped
- New sign-up from Lisbon
import { useState } from "react";
import { AnimatedList, Button } from "@rdloom/react";
const events = ["New sign-up from Lisbon", "Order 1042 shipped", "Refund issued for order 1037", "Comment on the roadmap page", "Backup finished"];
export default function AnimatedListLiveFeedExample() {
const [count, setCount] = useState(2);
const shown = events.slice(0, count).reverse();
return (
<div className="flex w-full flex-col items-center gap-4">
<Button variant="secondary" isDisabled={count >= events.length} onPress={() => setCount((n) => n + 1)}>
Add an event
</Button>
<AnimatedList announce className="w-full max-w-sm" aria-label="Recent events">
{shown.map((text) => (
<div
key={text}
className="rounded-[var(--rd-radius-control)] border border-[var(--rd-color-border-default)] bg-[var(--rd-color-surface-raised)] px-4 py-3 text-sm text-[var(--rd-color-text-default)]"
>
{text}
</div>
))}
</AnimatedList>
</div>
);
}API Reference
Defined by the spec. Components also accept the props of the React Aria component they wrap.
| Prop | Type | Default |
|---|---|---|
childrenrequiredThe items. Each child becomes one list item; give each a stable key so only genuinely new items animate. | node | none |
delaySeconds between one item appearing and the next, for items that arrive together. | number | 0.15 |
durationSeconds each item takes to slide in. | number | 0.4 |
announceMarks the list as a polite live region so screen readers announce items that are added later. Leave it off for a static list. | boolean | false |
isStillShows every item at once with no movement. Moving content should be stoppable. | boolean | false |
Accessibility
Role list, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.
Keyboard
Not interactive.
Screen readers announce
- Read as a list with its number of items
- With announce on, items added later are read out politely, once, without interrupting
What your code must do
- A real list: ul with one li per item, so the item count is announced
- Every item is real DOM in the server HTML and visible without JavaScript or CSS animation
- Stands still for visitors who ask for less motion (prefers-reduced-motion), and with isStill or inside an rdm-still container
- Each item moves once and stops, so nothing keeps moving and nothing flashes (WCAG 2.2.2, 2.3.1)
- Items keep their own focus order and content; the animation never moves focus
- Optional: it is a separate component, so projects that do not add it carry none of its code
Guidelines
Use it when
- A feed or activity log where new entries arrive
- A short list that should feel built up rather than dropped in
Avoid it when
- Long lists: staggered delays make the last items wait
- Lists people scan quickly or sort and filter often
Don't
- A delay so long that content is hidden for several seconds
- Turning on announce for a list that changes every second
Design tokens
The semantic tokens this component uses. Change them once and every component follows; see Design tokens.
--rd-color-text-default