Event Stream
A live tail of analytics events with their payloads — the tool for debugging the tracking itself. Autoscroll pauses when you scroll away and the list is capped rather than unbounded.
src/components/ui/event-stream.tsxAbout
From the component's own source, where it was written.
A live tail of analytics events, newest first.
**The debugging tool for the tracking itself.** Funnels and dashboards show what was recorded; this shows what is *arriving*, right now, with its properties — which is the only way to answer "did that click fire the event, and did it carry the right payload" without opening a network panel.
**Autoscroll pauses when you scroll away, and resumes at the top.** A stream that yanks you back to the newest row every time one arrives makes reading any event impossible — the thing you were looking at is gone before you finish. Scroll position is the intent signal, so no toggle is needed for the common case, and the explicit pause button exists for when the rate is high enough that even hovering is a fight.
**The list is capped and drops the oldest.** An unbounded live list is a memory leak with a UI: at a few hundred events per minute a tab left open over lunch is tens of thousands of nodes. limit is the ceiling, and the count of what was dropped is shown rather than silently forgotten.
Rendering is newest-first with aria-live="off" deliberately: announcing every arriving event would make a screen reader unusable. The count is announced politely instead.
Install
npx astralyx-ui add event-stream
Usage
import { EventStream } from '@/components/ui/event-stream'
<EventStream events={events} limit={500} />Composer
Change the props and the source below follows.
Event stream
9<EventStream
events={events}
filterable={true}
height={280}
/>Examples
A tail, with payloads
<EventStream events={events} />API
Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.
EventStream
Extends Omit<ComponentProps<'div'>, 'onSelect'>.
| Prop | Type | Default | Description |
|---|---|---|---|
| events | StreamEvent[] | required | { id, name, at, properties?, kind?, user? }. Newest first. |
| limit | number | 500 | An unbounded live list is a memory leak with a UI. Dropped rows are counted, not silently forgotten. |
| height | number | 360 | — |
| filterable | boolean | true | Filter box over event names. |
| onSelect | (event: StreamEvent) => void | — | — |
| colorFor | (kind: string) => string | — | Kinds mapped to a CSS colour. |
| paused | boolean | — | — |
| onPausedChange | (paused: boolean) => void | — | — |
| timeFormat | (date: Date) => string | DEFAULT_TIME | — |
| emptyLabel | string | 'Waiting for events…' | — |
| filterPlaceholder | string | 'Filter by name' | — |
| label | string | 'Event stream' | — |
| is | the tracking | — | Funnels show what was recorded; this shows what is arriving, with its payload — the only way to answer "did that click fire the event, and was it right" without a network panel. |
Types
StreamEvent
A live tail of analytics events, newest first.
| Field | Type | Description |
|---|---|---|
| id | string | — |
| name | string | — |
| at | Date | string | — |
| properties? | Record<string, unknown> | Shown expanded under the row. |
| kind? | string | Colours the dot — 'error', 'page', whatever you group by. |
| user? | ReactNode | — |
Behaviour
| Topic | Detail | Description |
|---|---|---|
| autoscroll | scroll is the intent | A stream that yanks you to the newest row makes reading any event impossible. It follows only while you are already at the top. |
| aria-live | off, deliberately | Announcing every arriving event makes a screen reader unusable. The count is announced politely instead. |