Preview
JSONL Preview
JSONL (one JSON value per line, also called NDJSON) rendered as a virtualized list with click-to-expand detail.
Extensions: jsonl, ndjson
Format
Each line is a complete, independent JSON value. Whitespace inside a value is allowed (the value is one logical entity even if it spans visually), but the convention is one line per object.
{"ts": 0.000, "data": [0.0, -1.57, 0.0]}
{"ts": 0.010, "data": [0.0, -1.56, 0.01]}
{"ts": 0.020, "data": [0.01, -1.55, 0.01]}This is the format used by every useSegment view's segment cache and by dreamlake-py for its track chunks.
Loading strategy
Fetch (with optional Range) → split on \n → parse each line lazily as the user scrolls. The split + parse path is streaming-aware: parsing a single line never requires holding the whole array in memory.
const text = await fetcher(url, ...).then(r => r.text())
const lines = text.split('\n').filter(Boolean)
// rows materialized on demand by the virtual listClick-to-expand split panel
The list shows one row per line — a compact summary (first ~80 chars of the JSON). Clicking a row opens a side panel rendering the full value through a syntax-highlighted JSON view, with collapsible nested objects and arrays.
┌─ rows ─────────────────────┬─ detail ──────────────┐
│ {"ts": 0.000, "data": ...} │ { │
│ {"ts": 0.010, "data": ...} │ "ts": 0.010, │
│ {"ts": 0.020, "data": ...} │ "data": [ │
│ {"ts": 0.030, "data": ...} │ 0.0, │
│ ... │ -1.56, │
│ │ 0.01 │
│ │ ] │
│ │ } │
└────────────────────────────┴───────────────────────┘The detail panel is virtualized too — opening a 10 MB JSON object with 100k keys does not freeze the tab.
Virtual scrolling
Same approach as CSV: only visible rows are mounted. A 1M-line JSONL renders in ~30 ms.
Soft size limit
Default: 10 MB. Range fetch → drop incomplete trailing line → truncation banner.
<FilePreview url={url} limits={{ jsonlMaxBytes: 100 * 1024 * 1024 }} />If a line fails to parse (malformed JSON), the row renders with a warning glyph and the original text. The previewer never crashes on bad input.
Live demo
import { FilePreview } from '@vuer-ai/vuer-m3u/preview'
export function MyComponent() {
return (
<FilePreview url="/vuer-m3u-demo/preview/tabular/events.jsonl" />
)
}