D
DreamLake

Preview

CSV / TSV Preview

Tabular files rendered as a virtualized grid. Handles million-row files without choking the DOM.

Extensions: csv (comma), tsv (tab)

Custom parser

The previewer ships its own RFC 4180-ish parser rather than depending on a CSV library. The parser is a single state machine that handles:

  • Quoted fields"hello, world" is a single field even with embedded delimiters.
  • Escaped quotes"" inside a quoted field becomes a literal ".
  • Embedded newlines"a\nb" is one field with a newline in it.
  • Mixed line endings\r\n, \n, and bare \r.
  • Trailing delimitersa,b, parses as three fields.

The parser is hand-written for two reasons:

  1. Bundle size — under 2 KB minified.
  2. Streaming + truncation — when a soft limit truncates the file mid-row, the parser drops the incomplete final row. A library like papaparse would yield a partial row instead.

Virtual scrolling

Both row dimension (vertical) and column dimension (horizontal, when wide) are virtualized. Only visible cells are rendered to the DOM. A 100k × 50 grid renders in ~16 ms on first paint with ~80 cells in the DOM at any time.

The header row is sticky; column widths are measured from the first 100 rows then frozen.

Soft size limit

Default: 10 MB. A Range: bytes=0-10485759 request fetches the prefix. The parser scans backwards from the byte cut to the last newline, drops everything after, and surfaces a truncation banner:

Showing 142,318 rows from first 10.0 MB of 44.8 MB

This is what the "soft limit + drop incomplete row" pattern in Size Strategy actually means. The user sees a complete tail row, never a half-row.

<FilePreview url={url} limits={{ csvMaxBytes: 100 * 1024 * 1024 }} />

TSV

.tsv files use the same parser with the delimiter set to \t. RFC 4180 quoting rules apply identically.

Live demo

The first tile is a small CSV that renders entirely. The second tile reuses the same small file but lowers limits.csv to 1 KB via the prop — the soft-limit Range cutoff and TruncatedNotice fire identically to a real >10 MB file, so the docs can demonstrate the UX without committing a multi-MB fixture.

Loading demo...
import { FilePreview } from '@vuer-ai/vuer-m3u/preview'

export function MyComponent() {
  return (
    <FilePreview url="/vuer-m3u-demo/preview/tabular/small.csv" />
  )
}

Cross-links