WebberUI

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.

Loading preview…
npx shadcn@latest add https://webberui.com/r/activity-feed.json

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

5
1200
<ActivityFeed />

Installation

npx shadcn@latest add https://webberui.com/r/activity-feed.json

Or, 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

PropTypeDefaultDescription
itemsActivityFeedItem[]The events, ordered chronologically (oldest → newest)
variant"default" | "timeline" | "compact""default"Layout style
insertAt"top" | "bottom""top"Where new events are inserted visually
maxnumberMaximum number of items to show; beyond it the newest are kept and older ones fade out and are removed
relativeTimebooleantrueShow times relatively (such as "3 minutes ago"); when off, HH:MM is shown
localestringLocale for time formatting (BCP 47)
highlightDurationnumber1200How long the background flashes for a newly arrived item (milliseconds); 0 disables it
emptyStateReact.ReactNodeWhat to show when the list is empty
labelstring"動態消息" (Activity feed)Accessible label for the list
classNamestringClass appended to the <ol> container

ActivityFeedItem

FieldTypeDescription
idstringStable unique identifier; the animation pairs previous and next state by it
titleReact.ReactNodePrimary content (a single-line title)
descriptionReact.ReactNodeSecondary text (omitted in the compact style)
iconReact.ReactNodeIcon on the left; when not provided, a small accent-colored dot is shown
metaReact.ReactNodeAttached content, shown below the description (omitted in the compact style)
timestampDate | number | stringEvent 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 beyond max fade out and exit.
  • Relative time: with relativeTime on, times refresh automatically every 30 seconds; the timer is cleaned up when there is no timestamp or when the component unmounts. Timestamps are computed against Date.now(), so the time nodes use suppressHydrationWarning to tolerate SSR/client differences.

Accessibility

  • The container carries role="log" plus aria-live="polite" and aria-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 a title carrying 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.

On this page