Skip to content
PortBay

Visual editor

A visual editor for your codebase, not a copy of it

Open your project's own .test URL in your own browser. PortBay injects an edit bar into the page, and the element you click resolves to a file, a line and a column you can edit in place.

21 stacksWrites to your sourceOpen source
acme-shop.test
BETA
Sign in
New season
Built for the long way home.

Hard-wearing gear, quietly designed. Free shipping over $75.

Shop the drop

Harbour tote

$210Add

Trail pant

$145Add

Wool crew

$98Add
0 pending edits@media ≤ 9911280 × 800
listings.blade.php
Open the project the way you always do

Start the project and visit its .test hostname in Chrome, Safari or anything else. The bundled Caddy edge routes the page through PortBay's edit proxy, which injects the bar into a shadow root. There is no app webview and nothing to open on the side.

Services

*.test
Domains
PHP 8.4
Runtimes
MySQL
Databases
Mailpit
Mail
share
Tunnels
claude
Agents
Sep 2026
SuMoTuWeThFrSa
123456789101112131415161718192021222324252627282930
Click an element

The bar switches from Preview to Inspect to Edit. Selecting an element resolves it to an authored coordinate — the file, line and column that produced it — through five anchor tiers, starting with the dev plugin's location stamp and falling back through a unique id, tag plus DOM ordinal, and more when it is absent.

Checkpoints

Today
Yesterday
Change the thing you are looking at

Text, classes, attributes and styles, plus structural edits — insert, delete, duplicate, move. Double-click to type into the page directly. The right-hand rail carries layout, spacing, typography, borders and effects, and a Tailwind token you rename is rewritten everywhere it is referenced in the same save.

Round the listing CTA and warm its border.

Done. Two files, 23 bytes. Nothing else moved — open the diff?

Ask the agent to change this page…
Pull the price into the accent colour
Save, and read what actually changed

The write goes through the same engine the in-app Apply uses: a surgical splice into the byte span, never a parse-and-reprint. Comment placement, quote style, trailing commas and key order outside the patched span come back byte-identical.

Tailwind tokens

Slate

+

Gray

+

Zinc

+

Tailwind tokens

Cyan

+

Blue

+

Indigo

+
Review the diff, or put it back

Every save sits on a shadow-git checkpoint kept outside your own history. The Diff button shows the working diff against it, and revert restores the pre-apply snapshot — per edit or all of it.

...and so
much more

Click resolves to a coordinatea.btn-primary
resources/views/listings.blade.php:42:18
Availability
Pro plan + the early_access entitlement + Settings → early-access opt-in. macOS Apple Silicon.
Toggle a class, the file changes
Stacks covered
Static HTML, React, Vue, Svelte, Next.js, Astro, Angular, Remix, Nuxt, SolidStart, Qwik, Laravel, Livewire, Inertia, Rails, Django, WordPress, WordPress block themes, Hugo, Jekyll, Eleventy.
The write, in bytes
listings.blade.php:42:18
rounded-mdrounded-full
14 bytes written · nothing else moved
Write lanes per stack
Text, attribute, class and page settings. A standing cross-stack test drives all four against all 21; a lane that cannot work on a stack has to refuse out loud, in a sentence the test checks for.
Three modes, one bar
How the file is written
A byte splice into the authored span. No formatter runs, and no marker attribute is written into your source.
One canvas, every width
1280px
Structural edits
Insert, delete, duplicate and move. Extract-to-component is narrower — Astro, JSX/TSX, Svelte and Vue — and refuses spans carrying a template expression rather than emitting source that will not build.
21 stacks, all four write lanes
LaravelRailsDjangoNext.jsAstroWordPress
Page settings and SEO
Title, description, robots, canonical, og:, twitter:, JSON-LD and custom head/body code. WordPress and WordPress block themes refuse this lane and say why.
Click resolves to a coordinatea.btn-primary
resources/views/listings.blade.php:42:18
CMS records in the same panel
Payload, Sanity, WordPress, Strapi 5 and a PortBay-managed database. Strapi 4 is refused by name.
Toggle a class, the file changes
Agent write-back over MCP
portbay_editor_apply, plus working-diff, history, restore-preview and restore. A dry run first, then an exact file consent list, then a human approval.
The write, in bytes
listings.blade.php:42:18
rounded-mdrounded-full
14 bytes written · nothing else moved
Breakpoint canvas
One canvas at a time. There is no multi-frame infinite canvas and it is not planned — see the FAQ.
Three modes, one bar
Runs while the project is publicly tunnelled
A project with a running tunnel is removed from the eligible set, so the bar and its write endpoints never answer public traffic.

Visual editor

Finding the element by hand

Without a visual editor the loop is: see it in the browser, guess which file it lives in, grep for a string you hope is unique, count how many other places share the class, then edit and alt-tab back to check. On a Blade or ERB template with a partial three directories away, the guess is the expensive part.

Get started

PortBay resolves the element you clicked to a file, line and column across 21 stacks, and replaces only the bytes that changed.

FAQ

Frequently asked questions

How is PortBay's visual editor different from Onlook?

Three ways, and one of them favours Onlook. PortBay writes by splicing the exact byte span in your file, so authored formatting survives and no marker attribute is added to your source; Onlook writes data-oid attributes into your files and reprints them through Prettier. PortBay runs locally against your own dev server on 21 stacks including Laravel, Rails, Django and WordPress; Onlook is Next.js plus Tailwind in a cloud sandbox. In Onlook's favour: it has a multi-frame infinite canvas and PortBay does not. PortBay has one breakpoint canvas, that was a deliberate decision rather than a missing feature, and a designer who works across frames will notice immediately.

Does PortBay's visual editor write markers into my source?

No marker lands in your files. The fastest way to identify an element is a data-pb-loc location stamp, and that is applied by the dev-server transform on the way to the browser, never written back into your source. When the stamp is not there the edit is not refused: four more anchor tiers follow it, starting with a unique id that matches exactly one opening tag across the project's authored markup, then tag plus the captured DOM ordinal.

Which frameworks does PortBay's visual editor work with?

Twenty-one, checked by a standing test rather than a README: static HTML, React, Vue, Svelte, Next.js, Astro, Angular, Remix, Nuxt, SolidStart, Qwik, Laravel, Livewire, Inertia, Rails, Django, WordPress, WordPress block themes, Hugo, Jekyll and Eleventy. The test drives four write lanes — text, attribute, class and page settings — against every one of them and reads the changed bytes back off disk, and any lane that cannot work on a stack has to refuse in a sentence the test checks for. Page settings is the one lane with real gaps: both WordPress rows refuse it.

Can an AI coding agent make the same edits through PortBay's visual editor?

Yes, through the same write-back engine over MCP. portbay_editor_apply is a two-step tool: the agent calls it with dryRun first and gets back the exact set of files the planner would write, which is not just the files it named, then calls again passing every one of those paths back as an exact consent list. If the list does not match the plan the call refuses and writes nothing. The real write also blocks on a human approval, and returns a snapshot id that undoes exactly that apply.

Can I use PortBay's visual editor on the free plan?

No. It needs a Pro plan with the early-access entitlement and the early-access opt-in turned on in Settings, and it is not compiled into the open-source build at all. It is macOS only, and it will not run while the project is shared over a public tunnel: a project with a running tunnel is dropped from the eligible set so the edit bar and its write endpoints never answer public traffic.