Skip to content

Scope & Limits ​

What v1 deliberately does not do, and why.

Not supported (friendly errors) ​

CaseBehavior
Legacy .xls (BIFF8)LEGACY_FORMAT error with a "re-save as .xlsx" hint. OLE2/BIFF is a different binary world; a future optional adapter could bring SheetJS in, but v1 keeps the dependency chain clean.
.ods / other suites (also ZIP packages)CORRUPT error — they are ZIP archives without an xl/workbook.xml, which is reported as "not a valid xlsx".
XML/HTML "spreadsheets" (SpreadsheetML 2003, HTML-table .xls)UNSUPPORTED error — they are text but not CSV, so rendering them as a data grid is meaningless; re-save as a real .xlsx.
Corrupt dataBroken ZIP structure (truncated files, …) or a workbook with no sheets at all → CORRUPT; not a ZIP and no readable text either → UNSUPPORTED (the format cannot be identified).
Environments without WebAssembly / engine load failureWASM error — xlsx parsing is WASM-only in v1 (there is no pure-JS fallback reader for xlsx); a 404 asset URL, a CSP that forbids WebAssembly or a network failure reports WASM too. CSV still parses without WebAssembly.

Rendered with known approximations ​

  • Rich text runs render as their concatenated plain text; run-level styling is on the roadmap (the current model keeps only the joined text, so restoring runs will need a parser addition).
  • Pattern fills (hatched patterns like gray125) render as their background/foreground solid approximation; solid and gradient fills render exactly.
  • Rotated text (textRotation) is clipped to the cell box when it does not fit — Excel also truncates rotated text that exceeds the cell, but its clipping follows the rotated text run rather than the axis-aligned cell rectangle, so edge cases near the diagonal differ slightly.
  • Number columns narrower than their content clip instead of showing Excel's #### (real #### needs text measurement per cell — not worth the scroll cost yet).
  • External hyperlink URLs are not rendered in v1; the hyperlink styling (blue/underline from the file's font) still shows because it is ordinary font data. Tooltips are not surfaced either.
  • rightToLeft sheets currently render left-to-right (the flag is parsed and carried in the model).
  • Conditional formatting and data bars / icon sets are not applied.
  • Charts, images, shapes are not rendered.
  • Row/column grouping (outline levels) is neither parsed nor drawn.

CSV encodings ​

UTF-8 (with or without BOM) and GB18030 are detected automatically. UTF-16 (FF FE / FE FF BOM) CSV files are detected as binary and rejected with UNSUPPORTED — re-save them as UTF-8 first.

Formulas ​

Formula cells render their cached <v> values — the same convention as SheetJS ("SheetJS does not evaluate formulas") and exceljs. A formula saved by a non-Excel writer without a cached value renders as an empty cell.

Scale ​

Parsing is not streaming (OOXML parts cross-reference each other; browsers cannot stream-parse a zip of interdependent parts) — the whole file is read into memory inside the worker. 100k × 10 cells parse in ~1.5s (measured); virtual scrolling keeps the DOM at viewport size regardless of file dimensions. Multi-hundred-MB files will hit memory limits before anything else. The repo's performance test asserts a different, looser bound: 100k × 8 model build < 4s, measured inside happy-dom without real rendering, and skipped in CI and the release pipeline (RUN_PERF=0).

Row-count ceiling (a browser limit, not memory): the grid is one tall container element, and at 20px per row (15pt) roughly 890k rows (~17.9M px) hit the element-size cap in Firefox / Safari — rows past that point are unreachable. Chrome's cap is ~33.5M px (about 1.67M rows). Headers and row/column labels stay viewport-sized either way; only the scrollable range is cut short. Previewing a full sheet (1,048,576 rows) needs the renderer to switch to chunked offsets first.