Svelte
Inline Edit
Edit the words on the page. The file changes.
Press a key, click a paragraph, type. The edit is written straight back into the .svelte file it came from. No agent, no CMS, no desktop app — the compiler records
where every string lives, and the dev server splices the file.
The awkward part
Rendered text has no obvious way back to the template that produced it. And at runtime these two are indistinguishable — both are one element rendering one text node:
<p>Static prose</p> ← a byte range in the file
<figcaption>{shot.caption}</figcaption> ← text lives in a JS array They need completely different writes, so guessing from the DOM would eventually splice a
literal over {shot.caption} and destroy the expression. The decision
has to be made where the answer actually exists: at compile time. The plugin parses every .svelte file and stamps each element it can safely edit, so the browser's rule becomes
trivially correct — editable if the mark is there, inert if it isn't.
Three shapes it can write
Plain prose
<p>Static prose.</p> Marked with a byte range in the file. The simple case, and the one every visual editor already handles.
Prose with inline tags
<p>with <strong>emphasis</strong>.</p> The whole inner range is the unit. The browser rebuilds the markup through a strict allowlist and the server re-parses it before writing, so a bad rebuild fails loudly rather than corrupting the file.
Text out of an {#each}
{#each cards as c}<h3>{c.title}</h3> The one that blocks every other tool — and usually where most of the copy actually lives. On the page this was built for, 60 of 110 editable nodes came out of arrays.
The array form deliberately carries no index — that's a runtime fact the compiler can't see. The server finds the entry by matching the text being replaced instead, which makes the write self-verifying and fails safe on duplicates.
Refusing is the whole game
Anything it can't put back faithfully is never offered. No outline, no caret, no surprise in your diff.
- A <pre>, or anything with preserving white-space Its layout is its content, and writes collapse whitespace.
- Prose containing an <a href> or any attributed tag The DOM cannot tell you an onclick={…} handler ever existed.
- Text from data.items or a function call There is no literal in the file to splice.
- Two array entries holding identical text Ambiguous. It refuses rather than guessing which one you meant.
- Anything mixing markup with an {expression} The expression is source the DOM does not remember.
What it looks like
Why it didn't already exist
Svelte already had the read-only half. The official inspector jumps you to the right line,
and svelte-trace stamps source locations — then stops, describing itself as a foundation
for other tools. Nobody built the tool.
What does write back is elsewhere: Onlook is React-only and a desktop app, stagewise routes every edit through a language model, and the CMS visual editors edit CMS content rather than your files. Splicing the source directly is faster than all of them, costs nothing, and works on a plane.
It exists because I was writing a long project page by hand and got tired of hunting for which array a caption lived in. That's still the honest use case: fixing your own copy, in place, without breaking flow.
Two lines and a keypress.
Add inlineEdit() to your Vite plugins. It's dev-only by construction — nothing in
it reaches a production build.