Signature
DataStream
Live append-only log feed in a fixed-height window — new rows hard-cut in at the top with a decaying signal flash (reduced-motion aware).
● LIVE
STDOUT // LIVE
"use client";import * as React from "react";import { DataStream, type StreamEntry, type StreamTint,} from "@/registry/okibi/ui/data-stream";const POOL: { text: string; tint: StreamTint }[] = [ { text: "link established // node 0x4A2", tint: "success" }, { text: "packet received // 1.4kb", tint: "muted" }, { text: "latency spike // 320ms", tint: "warning" }, { text: "auth token refreshed", tint: "info" }, { text: "checksum mismatch // retrying", tint: "destructive" }, { text: "telemetry frame // ok", tint: "signal" },];function stamp() { return new Date().toTimeString().slice(0, 8);}export default function DataStreamDemo() { const [entries, setEntries] = React.useState<StreamEntry[]>([]); const idRef = React.useRef(0); React.useEffect(() => { const push = () => { const p = POOL[Math.floor(Math.random() * POOL.length)]; setEntries((prev) => [ ...prev.slice(-20), { id: idRef.current++, text: p.text, tint: p.tint, time: stamp() }, ]); }; push(); const id = setInterval(push, 1500); return () => clearInterval(id); }, []); return <DataStream title="STDOUT // LIVE" entries={entries} max={7} className="w-full max-w-md" />;}npx shadcn@latest add https://okibi.cndr.dev/r/data-stream.jsonInstallation
Install the theme first, then add the component:
npx shadcn@latest add https://okibi.cndr.dev/r/data-stream.jsonAdd the okibi building blocks it composes: console-surface.
Copy the source from the Code tab above into components/ui/data-stream.tsx. It uses the cn helper and the okibi theme tokens — install the theme first if you haven't.
Usage
import { DataStream } from "@/components/ui/data-stream"
const entries = [
{ id: 1, text: "link established // node 0x4A2", tint: "success", time: "12:00:01" },
{ id: 2, text: "packet received // 1.4kb", tint: "muted", time: "12:00:02" },
]
<DataStream title="FEED // 0x4A2" entries={entries} max={8} />Examples
Tints
A static feed showing the six semantic row tints — signal, success, warning, info, destructive, and muted — at a glance, no live timer.
● LIVE
STDOUT // TINTS
08:14:01telemetry frame // ok
08:14:02link established // node 0x4A2
08:14:03latency spike // 320ms
08:14:04auth token refreshed
08:14:05checksum mismatch // dropped
08:14:06log buffer idle // standby
"use client";import { DataStream, type StreamEntry } from "@/registry/okibi/ui/data-stream";// Static, seeded rows — one per tint — so the semantic palette is visible at a// glance without relying on the live append timer. Ordered oldest-first; the// component reverses for display, so listing them in reverse here keeps the// rendered order signal → success → warning → info → destructive → muted.const ROWS: StreamEntry[] = [ { id: 6, text: "log buffer idle // standby", tint: "muted", time: "08:14:06" }, { id: 5, text: "checksum mismatch // dropped", tint: "destructive", time: "08:14:05" }, { id: 4, text: "auth token refreshed", tint: "info", time: "08:14:04" }, { id: 3, text: "latency spike // 320ms", tint: "warning", time: "08:14:03" }, { id: 2, text: "link established // node 0x4A2", tint: "success", time: "08:14:02" }, { id: 1, text: "telemetry frame // ok", tint: "signal", time: "08:14:01" },];export default function DataStreamTintsDemo() { return ( <DataStream title="STDOUT // TINTS" entries={ROWS} max={6} className="w-full max-w-md" /> );}API Reference
DataStream
| Prop | Type | Default | Description |
|---|---|---|---|
entries | { id; text; tint?; time? }[] | – | Log entries, oldest first; newest renders at the top. |
max | number | 8 | Rows in the fixed-height ring-buffer window. |
title | string | – | Optional mono header title. |
Accessibility
- The feed is a live region:
role='log'witharia-live='polite'andaria-relevant='additions', so appended rows are announced. - Named by the visible header via
aria-labelledbywhen atitleis set; otherwise it falls back to anaria-labelofLive data streamso the log is always named. - The leading rails, the one-shot signal flash, and the
›marker are decorative and markedaria-hidden. - Reduced-motion safe: the new-row flash is gated to a no-op so nothing animates when motion is off.
- Pass stable, unique
ids per entry — duplicate ids collide as React keys and can disrupt row identity.
Guidelines
Do
- Pass
entriesoldest-first; the newest renders at the top of the window. - Set
maxto size the fixed-height ring buffer so the panel never reflows as it fills. - Use the
tintper row to signal severity acrosssignal,success,warning,info,destructive, andmuted.
Don't
- Do not point a polite log at a torrent of rows — a screen reader will narrate every addition.
- Do not reuse entry
ids across different rows; identity and announcement depend on them being stable. - Do not assume an empty all-padding window reads as connected; it looks the same as not-yet-started.