Activity Feed
A live list that inserts items automatically — new events push in from the top and existing rows reflow smoothly with FLIP — with timeline and relative-time support.
npx shadcn@latest add https://webberui.com/r/activity-feed.jsonPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<ActivityFeed />
Installation
npx shadcn@latest add https://webberui.com/r/activity-feed.jsonOr, once registries are configured in components.json, install it as @webberui/activity-feed.
Usage
Order items chronologically (oldest → newest) and just keep pushing new events onto the end of the array; the component pairs items up for animation by id, so new items reveal and existing ones reflow automatically.
import { ActivityFeed, type ActivityFeedItem } from "@/components/ui/activity-feed";
const items: ActivityFeedItem[] = [
{ id: "1", title: "System started", timestamp: Date.now(), accent: "green" },
{ id: "2", title: "User signed in", description: "From Taipei", timestamp: Date.now() },
];
<ActivityFeed items={items} max={8} />Styles
Use variant to switch between three layouts: default (card rows), timeline (a connecting timeline on the left), and compact (a trimmed single line).
<ActivityFeed items={items} variant="timeline" />Props
| Prop | Type | Default | Description |
|---|---|---|---|
items | ActivityFeedItem[] | — | The events, ordered chronologically (oldest → newest) |
variant | "default" | "timeline" | "compact" | "default" | Layout style |
insertAt | "top" | "bottom" | "top" | Where new events are inserted visually |
max | number | — | Maximum number of items to show; beyond it the newest are kept and older ones fade out and are removed |
relativeTime | boolean | true | Show times relatively (such as "3 minutes ago"); when off, HH:MM is shown |
locale | string | — | Locale for time formatting (BCP 47) |
highlightDuration | number | 1200 | How long the background flashes for a newly arrived item (milliseconds); 0 disables it |
emptyState | React.ReactNode | — | What to show when the list is empty |
label | string | "動態消息" (Activity feed) | Accessible label for the list |
className | string | — | Class appended to the <ol> container |
ActivityFeedItem
| Field | Type | Description |
|---|---|---|
id | string | Stable unique identifier; the animation pairs previous and next state by it |
title | React.ReactNode | Primary content (a single-line title) |
description | React.ReactNode | Secondary text (omitted in the compact style) |
icon | React.ReactNode | Icon on the left; when not provided, a small accent-colored dot is shown |
meta | React.ReactNode | Attached content, shown below the description (omitted in the compact style) |
timestamp | Date | number | string | Event time; when provided it is shown in the top-right corner |
accent | "neutral" | "blue" | "green" | "amber" | "red" | "violet" | Accent color |
How it works
- Data driven: the list is entirely controlled by
items(controlled mode). The component holds no internal item state — you only maintain one array and push onto its end, and insertions, removals, and reorders all animate automatically. - Reveal and reflow: new items reveal with opacity plus offset plus a slight scale, while existing rows spring smoothly out of the way through Motion's
layout(FLIP); the oldest items beyondmaxfade out and exit. - Relative time: with
relativeTimeon, times refresh automatically every 30 seconds; the timer is cleaned up when there is no timestamp or when the component unmounts. Timestamps are computed againstDate.now(), so the time nodes usesuppressHydrationWarningto tolerate SSR/client differences.
Accessibility
- The container carries
role="log"plusaria-live="polite"andaria-relevant="additions", so newly inserted items are announced by screen readers while the initial batch is not re-announced. - Decorative icons, the highlight flash, and the connecting line are all marked
aria-hidden; times are rendered as semantic<time dateTime>with atitlecarrying the full time. - When the user has "reduce motion" enabled at the system level, FLIP reflow and the offset/scale are disabled, leaving only a minimal opacity fade in, and exits and insertions no longer move.
Animated Charts
Data-driven SVG charts that grow as they reveal — bars grow up from the baseline, lines and areas draw themselves along their stroke — triggered when they enter the viewport.
Animated Terminal
A command-line terminal that simulates typing line by line, with per-character command entry, output reveals, and looping playback.