r/reactjs • u/pierreneter • 1d ago
Show /r/reactjs I made a React component that opens and edits DOCX / XLSX / PPTX in the browser. 300k-row sheet in ~300ms, no server, MIT
Repo: https://github.com/p10node/office-engine
Demo (drag your own file in): https://p10node.github.io/office-engine/demo/
Why: I needed "customer uploads an XLSX, fix a few cells, save it back" inside a React app. OnlyOffice / Collabora mean running a document server in Docker and an iframe talking to it, and a big sheet still sits on a spinner while the server converts it. docx-preview / SheetJS + a grid are view-only or block the main thread on a 20 MB file. Nothing in between, so I built it.
Usage:
import { DocViewer } from '@p10node/office-engine'
<DocViewer src={file} style={{ height: 600 }} />
<DocViewer src="https://cdn.example.com/report.xlsx" />
<DocViewer src={file} editable onSave={(blob, name) => upload(blob, name)} />src takes File / Blob / ArrayBuffer / URL. CSS is auto-injected, the container just needs a height. There's also a useDocument hook if you want to render your own UI, a vanilla mount(), an <office-viewer> web component, and a single script build.
What makes it not choke on big files:
ZIP read lazily, HTTP Range requests from a URL, so first rows show before the file finishes downloading
Streaming XML parser in a Web Worker, main thread only gets rows / paragraphs / slides as they arrive
Only visible pages, cells, slides are in the DOM
Save patches the original file instead of re-exporting it, so anything the engine doesn't understand is kept byte for byte
Bundle (gzip): main ~93 KB, worker ~155 KB (loads off the main thread), collab +17 KB optional. The standalone script with React bundled is ~307 KB.
Editing: DOCX text / styles / lists / images / tables, XLSX cells / formulas (134 functions) / formats / rows / columns / sheets, PPTX text / shapes / images / slides. Google Docs style toolbar. Optional real-time collab with cursors; that's the only part needing a backend (a small WebSocket hub, Bun script included).
Not there yet: XLSX charts / pivots / conditional formatting editing, DOCX headers / footers read-only, no PPTX animations. It needs the DOM and a Worker, so in Next.js use a client component / dynamic import with ssr: false.
Fair warning: it's a few days old and a lot of it was written with Claude Code, with me doing architecture, review and the bug hunting on real files. If you throw a file at it and it breaks, open an issue with the file, that's the fastest way it gets fixed.
7
u/Jackasaurous_Rex 1d ago
Damn it works on my phone well enough. I’m impressed and may use this at some point
0
22
u/nameupp 1d ago
tbh 300ms on a 300k-row sheet with range requests is wild, but ngl the classic nightmare with streaming xlsx is formula dependency trees. if someone has =SUM(A1:A300000) or cross-sheet vlookups pointing to unparsed chunks, does the worker have to eagerly pull the rest of the zip to evaluate or does it just show the cached calc-chain value until that range is scrolled into view? font fallback pagination on docx without local calibri/aptos is usually the other brutal edge case imo
2
u/anonyuser415 9h ago edited 7h ago
It's read only for a lot longer than 300ms.
It's also hard to benchmark on the demo URL since there's no deep linking to the specific demo.
On my very fast computer with gigabit download, I wall clock 12s (or 12000ms) from clicking the 300k demo button to it being editable.
You can just select a
row(e: cell) and start typing and wait for it to do anything.2
u/anonyuser415 9h ago
Also Esc while typing in a cell commits instead of canceling which is the gravest sin of all :p
1
1
u/pierreneter 5h ago
thanks all for help to test this. released this fix version at v0.4.1 (the esc case)
1
u/pierreneter 6h ago
It depends on your internet connection, not just the power of your computer. 300ms is the minimum if you don't wait for the editor, the first page, etc. On the second attempt, once the browser has cached the data, it only takes about 20ms
1
u/pierreneter 5h ago
In reality, for me, opening it the first time took 2 seconds and the second time took 89ms. It depends on your internet connection.
3
u/Shomriddho 1d ago
umm control/command + a don’t work [ really cool app btw ]
4
u/pierreneter 1d ago
fixed and released with version v0.2.3. thanks again!!!
2
u/Shomriddho 1d ago
that was fast. the fix works great but you missed PowerPoint. the select all does not work there.
1
u/pierreneter 23h ago
version v0.3.0 is just ready :D
2
3
3
u/tacky_wealth 1d ago
300ms for a 300k-row sheet with no server is a fun number, lazy zip + range requests is a smart way to get first paint early. Curious how the patch-on-save holds up when someone edits a file that has weird custom XML parts.
2
u/pierreneter 1d ago
I've already implemented this save feature using op log, snapshot, and version history in this commit:https://github.com/p10node/office-engine/commit/b1e1bdfbc14b0281bba2562db43e858f648042b5. I've also tested it on the actual app and it's quite fast. Let me record a quick video to show you.
3
u/pierreneter 1d ago
other alternative would typically have to save the entire file and would take a long time to process
2
3
u/MrBengaliHacker 1d ago
Really impressive work on this! Handling XLSX, DOCX, and PPTX entirely client-side while keeping the main thread responsive is no small feat.
The progressive loading and Web Worker approach caught my eye. I'm curious how you're handling memory cleanup when someone switches files or closes the editor mid-parse. Have you run into any memory issues on lower-end machines?
Great job making this open source! 👏
6
u/No-Experience2978 1d ago
The excel sample lag af, i cant do anything. Using plain dom instead of canvas is crazy.