Typing in a 5,000-row table took 26 seconds per key. Here's how I got it to 24 ms.
Sarala is a free, open-source Markdown editor where the page you write is the page you read. There's no preview pane. Click a paragraph to edit its Markdown, click away and it renders in place. It started as a desktop a
Sarala is a free, open-source Markdown editor where the page you write is the page you read. There's no preview pane. Click a paragraph to edit its Markdown, click away and it renders in place.
It started as a desktop app built with Tauri and SolidJS, and it now runs in the browser too.
When I brought it to the browser, I benchmarked large files for the first time. Normal documents were fine. A 20,000-line document with thousands of paragraphs typed at about 14 ms per key.
Then I tried a single huge block:
| Document | Delay per key |
|---|---|
| Table, 5,000 rows | 26,028 ms |
| List, 20,000 items | 4,401 ms |
| Paragraph, 20,000 lines | 681 ms |
| Code block, 20,000 lines | 128 ms |
That's a 26-second wait for one letter.
Why windowing didn't save me
The editor already renders only the blocks near the viewport, so long documents stay light. But it does that per block. One giant table is one block, so it's always fully rendered.
The block you're editing was also rebuilt from scratch on every keystroke: parse the Markdown, replace its innerHTML, then walk every node to restore the caret.
The clue in the profiler
My first profile didn't add up. Three keys took about 1.9 seconds, but JavaScript accounted for only around 500 ms. The rest was the browser laying out the rebuilt block again.
So a faster parser wouldn't be enough. The fix had to stop touching the DOM.
Three separate bugs
A table component measuring everything. A row-reordering overlay re-measured every row on each keystroke, and its cost climbed quickly as the table grew.
A quadratic token walk. marked.walkTokens builds its result by repeatedly concatenating arrays. On a 20,000-item list, that cost 2.6 seconds, and nothing in my code read the result. A small linear walker took opening that list from 2.8 s to 0.4 s.
Slicing the rest of the document per character. Mapping a click to a source offset called source.slice(i) and ran an unanchored regex for every character. Clicking into a 1 MB block took 7.8 seconds. Each pattern can only match at its own first character, so it now checks that first.
Editing one line at a time
The big change: a very long block now edits as plain lines while it's active. Each source line is its own <span>, so the text content stays byte-identical to the Markdown.
When you type, the browser has already put the character on screen, so I don't redraw anything. The new text is spliced from the one edited line, with a length check that falls back to reading the DOM if anything looks wrong. Structural edits like Enter or paste patch only the lines that changed. When you click away, the block renders normally.
Browsers fought back
My first version used block-level line boxes, which made layout cheap. Then tests caught ArrowUp jumping to the top of the block in Chrome and WebKit. Inline spans behaved correctly in all three engines and cost almost nothing extra.
Tests also caught the End key doing nothing from the start of a line, and a native delete across two lines removing the wrong newlines. Speed is worthless if editing is wrong, so edits that cross a line now go through the source text.
The result
| Document | Before | After |
|---|---|---|
| Table, 5,000 rows | 26,028 ms | 24 ms |
| List, 20,000 items | 4,401 ms | 69 ms |
| Paragraph, 20,000 lines | 681 ms | 45 ms |
| Code block, 20,000 lines | 128 ms | 34 ms |
The trade-off is real: while you edit a very long block, you see Markdown rather than the styled view, and the app tells you so. A 20,000-item list still costs more than a frame, nearly all of it inside the browser's own editing code.
What I'd pass on: measure what the browser does, not only your JavaScript. And write the correctness tests before you trust the benchmark.
A quick tour
Here's the rest of what the editor does. These screenshots are from the desktop app for macOS, Windows and Linux.
The live editor. One page for writing and reading, with no split view.
Diagrams. Mermaid and D2 render right in the page.
Math. LaTeX typeset with KaTeX as you write.
Code. Syntax highlighting for more than 100 languages, in your theme.
Tables, tasks and callouts. Edit tables cell by cell and tick tasks with a click.
AI assistant, desktop only. It runs the coding agents on your own machine, and you approve each edit as a diff.
Voice typing. Dictation runs on your device.
Command palette. Every action is one Cmd/Ctrl+K away.
Themes. Thirteen built in, or bring your own base16 scheme.
On your phone. The browser version works there too, with a formatting bar above the keyboard.
Try it
The browser version needs no install and no account, and your documents stay on your device: https://web.sarala.solancer.com
Desktop apps for macOS, Windows and Linux: https://sarala.solancer.com
The source is on GitHub: https://github.com/solancer/sarala
I'd love to hear what breaks.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.










