KQ-1317 · ACTIVITY/STREAM

Activity Stream

A live activity feed where new events gather behind an "N new" pill instead of shoving the list under the reader: the faces behind them land on the pill on recoil and the count rolls on snap. Pressing it scrolls the feed to its top on glide and releases them in a cascade while everything below glides down, each revealed line keeping a wash that fades over two seconds; switching the grouping between person, type and none glides every line to its new seat, and relative times tick on a timer set for the next boundary any line will cross. The list is a role="feed" of articles with one roving tab stop — Up and Down move between lines, Page keys between articles, Home and End to the ends, Enter opens — and the kind chips are toggle buttons.

KQ-1317 · ACTIVITY/STREAM

Fieldline Ops

Live
24 updates
Teo Varga
Mara Lind
Route monitor
Rui Santos
Ama Okafor
Ilse Brandt
Noor Haddad
Kit Morrow
Mara Lind
Ama Okafor
Route monitor
Teo Varga
Rui Santos
Noor Haddad
Ama Okafor
Sol Arden
Ilse Brandt
Kit Morrow

live · up to date

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/activity-stream

Props

rate
number
default 12
How many events arrive per minute from incoming while live; 0 stops arrivals. Sets how fast the pill fills.
group
"actor" | "kind" | "none"
default "actor"
How the feed groups: consecutive events by one person, by one type, or one article per event. Changing it glides every line to its new seat.
pill
"avatars" | "count" | "off"
default "avatars"
How new events wait: behind a pill of faces and a rolling count, behind a plain count, or not at all — they slide in at the top as they land.
events
ActivityEvent[]
default defaultActivityEvents
The history, in any order: id, actor, kind, action, target, detail and at (Date or ms). Ids added after mount wait behind the pill like arrivals.
incoming
ActivityIncoming[]
default defaultActivityIncoming
Events still to come (no time yet), released in order at rate and stamped with the stream's clock; the list loops with fresh ids.
actors
ActivityActor[]
default defaultActivityActors
Who can act: id, name, an optional role shown in group headers and an optional tint (any CSS colour) for the avatar.
kinds
ActivityKind[]
default defaultActivityKinds
What can happen: id, label, plural and an optional 16px icon. Each kind present becomes a filter chip with its count.
now
number | Date
default defaultActivityNow
The time the stream starts from. Relative times are measured from it, never from the wall clock during render.
live
boolean
default true
The clock runs on from now in real time and incoming arrives. Off: the clock holds and nothing arrives.
filter / defaultFilter
string[]
default []
The kind ids shown; empty shows everything. Controlled or uncontrolled.
onFilterChange
(kinds: string[]) => void
default —
Fires from the chip that changed the filter, with the new kind ids.
onReveal
(events: ActivityEvent[]) => void
default —
The pill was pressed: fires with the events it brought into the feed, newest first.
onArrive
(event: ActivityEvent) => void
default —
An incoming event arrived, stamped with the stream's clock.
onOpen
(event: ActivityEvent) => void
default —
A line was pressed or opened with Enter.
groupWindow
number
default 30
Consecutive events further apart than this many minutes start a new group.
collapseAfter
number
default 3
Lines a group shows before a Show N more disclosure, whose height glides open to what its lines measure.
height
number
default 560
The panel's height in px; the feed scrolls inside it.
status
"ready" | "loading" | "error"
default "ready"
Whether the history has arrived: loading shows a skeleton and marks the feed busy, error a retry.
onRetry
() => void
default —
Try again was pressed after the history failed to load.
title
string
default "Activity"
The panel's heading.
label
string
default —
The panel's accessible name. Defaults to the title.
emptyLabel
string
default "No activity yet."
What an empty feed says.
formatTime
(at: Date) => string
default —
The absolute time in a line's title. Defaults to a fixed, locale-free "30 Sep, 14:05 UTC".
sound
boolean
default false
Play a plip for filter chips and Show more, and a pop when the pill reveals. Arrivals and ticks are always silent.
disabled
boolean
default false
Shows the feed but refuses filters, reveals and opens; arrivals keep gathering.
className
string
default —
Classes for the outer panel.