Skip to content
PortBay

Edit the template block of a .vue file from the browser

PortBay reads the template block of every single-file component and gives each element its file, line and column. Click it in the browser, change it, and the edit lands in that exact span of the .vue. Your script and style blocks are never touched. Pro, early access, opt-in.

The short answer

How do I edit a .vue file visually?

Most visual editors sold to Vue teams edit content, not components — they connect to a CMS or a data file, render your app around it, and let you change the words inside a slot. That is a different job from opening the single-file component and changing its markup, which is what people usually mean. PortBay does the second one. It stamps only the template block of each .vue file, so every element in it carries its file, line and column, and your script setup and style blocks are never scanned at all. Click an element in the running app, change its text, classes or attributes, and the change is spliced into that exact byte range of the SFC, with your formatting intact. The coordinate exists only in the HTML the browser receives; it is never written back to a file. Pro, early access, opt-in under Settings.

Verified against the product, 2026-09-05.

In the app

A Vue SFC, template block only

acme-shop · Board6 cards3 agents online
Pending2
infra
Rate-limit the API
P1
Dark mode polish
P2
Todo2
auth
Add OAuth login
P0Claude Code0/3oauth-login
Auto-dispatching
implement OAuth on app.test
db
Migrate to Postgres
P1
In Progress1
Fix flaky checkout test
P0
Done2
Set up Mailpit inbox
P2
Seed demo data
P2
1/5 · AssignA card lands in Todo and @claude is mentioned

PortBay runs your Vue app at its own .test URL with trusted HTTPS and dispatches board cards into it. The visual editor edits that same running app in your real browser — one live page at one breakpoint, not a multi-frame design canvas.

Walkthrough

Your first SFC edit

Four steps from a Vue project to a change committed in a .vue file. None of them adds a dependency.

  1. Install PortBay and add your Vue project
  2. Turn the visual editor on
  3. Start the project — the templates are already mapped
  4. Open Edit in browser and change a component

Install PortBay and add your Vue project

Homebrew installs the app and the bundled portbay CLI. Add the project folder; PortBay reads your package.json, recognises Vue on Vite, runs your dev server and serves it at its own .test hostname over trusted HTTPS.

brew tap portbay-app/portbay && brew install --cask portbay

Turn the visual editor on

It ships to Pro under early access and is off by default. Sign in to Pro, then flip the Early Access toggle. The open-source build does not contain the editor at all — it is not compiled in.

Settings › Account › Early Access

Start the project — the templates are already mapped

PortBay writes a vite.config.mjs into its own data directory that imports and spreads your config and adds its plugin, then starts the dev server with one --config flag. Nothing is written inside your project. The plugin applies while serving only, so vite build never loads it and no coordinate can reach a production bundle.

portbay start myapp

Open Edit in browser and change a component

The project's Visual editing section has one button. It opens your normal browser at your normal .test URL with the edit bar docked at the top, booting in Preview mode where the page stays fully interactive. Switch to Edit, double-click text to type into the live page, then Save to write to source. Lifting a chunk of a template out into its own .vue file is a single edit here — Vue is one of the four stacks where extraction is supported.

https://myapp.test
Without PortBay

What the stamper reads in a .vue file, and what it ignores

A single-file component is three languages in one file, and treating it as one blob is how a tool ends up putting an attribute inside a style rule. PortBay carves the template out first and never looks anywhere else.

The usage line is the one worth noticing. Because a .vue template is markup, a component tag carries its own coordinate — so an element that PriceCard rendered still traces back to where you used it. A .jsx or .tsx file does not get that tier, and the React page says why.

Questions

Asked before downloading

Only the template blocks. The scanner walks the file, finds each template element, and marks its interior as the one region that may contain markup. A script or script setup block is JavaScript and a style block is CSS, and neither is ever scanned for elements or written to. That is why a class name that also appears inside a style rule cannot be confused for a class attribute, and why nothing PortBay does can reach your component logic.

Yes, and this is the concrete advantage of an SFC over a JSX file. In markup, a capitalised or dotted tag is a component and nothing else, so the scanner can stamp the usage site safely. That means an element rendered by a child component still traces back to the line where you used it. In a .jsx or .tsx file the same tag shape can be a TypeScript generic parameter list, so that tier is dropped rather than guessed at — a real difference between the two lanes, and the reason a Vue project maps essentially everything you can click.

Bound attributes are refused by name, not silently skipped. If you drag a new image onto an img whose src is written as :src, v-bind:src or a shorthand from another framework, PortBay tells you the src is bound dynamically and that the URL in the source is not the URL the browser will request. Writing a literal over the binding would break the binding; writing to the bound expression would need to know where its value came from. Saying so is the finished answer, and the change belongs in the data.

No, and it says which rule it hit: a text run holding braces is a template expression, so PortBay refuses it and points you at the source rather than rewriting bytes that hold a binding. Static copy in the same template edits normally. There is a related detail worth knowing in the other direction — when PortBay has to write a literal pair of braces into a Vue template, it writes them as HTML character references, because Vue's tokenizer scans the raw source bytes for its delimiter and never decodes an entity first. The browser decodes it and the visitor sees the braces.

Not into your style scoped block. A style change becomes a Tailwind class rewrite when the project uses Tailwind and the utility would genuinely win the property — the editor checks that first, because adding a class that a more specific rule in your own CSS already outranks would change nothing on screen. When it would not win, the change goes to a PortBay override sheet and you get a notice saying so. The one thing that never happens is a change reported as saved that renders no differently. Design tokens are a separate and stronger lane: renaming a Tailwind token in your v3 config or a v4 @theme block rewrites every class reference to it across your markup in one save, spliced byte-for-byte so the rest of the file's formatting is untouched.

Nothing to install for Vue on Vite. The stamping plugin lives inside the PortBay binary, is written out to PortBay's own data directory, and reaches your dev server through a config generated outside your repository — uninstall PortBay and your package.json, lockfile and node_modules are byte-for-byte what they were. Nuxt is supported through its own injection path rather than this one, because nuxt dev takes no config flag, so PortBay extends it as a layer instead. Same plugin, same stamps, different seam.

PortBay's Vue visual editor is not a CMS. It edits the .vue files in your repository, which is the opposite end of the problem from the visual-editing products built around a content backend — those are good at letting an editor change words inside a slot and explicit that they do not open the components themselves. On price: the editor is a Pro feature, in early access behind an opt-in toggle in Settings, and it is not compiled into the open-source build. It attaches only to local .test hosts and refuses while a project is shared over a public tunnel. Everything else on this page — the hostname, the HTTPS, the dev server, the task board — is in the free app.

PortBay mascot — a friendly blue tugboat

Give your projects and your agents a real local home.

Download for macOS

Free & open source · macOS 11+ on Apple Silicon · Pro from $10/mo