Skip to content
PortBay

Inertia pages edit like Vite source, because that is what they are

Inertia is the best-supported stack in the Laravel family, because its pages are ordinary Vite source files. PortBay stamps the dev server it launches, so your page components get precise and structural editing with nothing installed. Pro, early access, opt-in.

The short answer

How do I visually edit Inertia pages in a Laravel app?

An Inertia application is two things at once — a Laravel back end and a Vue, React or Svelte front end compiled by Vite — and which half a visual editor can reach decides what it can do. The Vite half is the good half. PortBay launches your dev server, so it adds source-location stamping to it from a config generated outside your repo, with nothing to install; your page components then carry their file, line and column and get precise and structural editing. The Blade shell around them is a server-rendered template and still edits by matching markup. Page settings are resolved from the route's Inertia page name to that page component, where a Head element is written — created, with its import, if the component has none. Pro, early access, opt-in.

Verified against the product, 2026-09-05.

In the app

An Inertia page on the Vite lane

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 Inertia app at its own .test URL with trusted HTTPS, starts PHP-FPM and your Vite dev server, and dispatches board cards into it. The visual editor edits that same running app in your real browser — one live page, not a multi-frame design canvas.

Walkthrough

Your first Inertia page edit

Four steps, and none of them installs anything. Inertia gets here by being a Vite project wearing a Laravel coat.

  1. Install PortBay and add your Inertia project
  2. Turn the visual editor on
  3. Start the project — your Vite server gets the stamping
  4. Open Edit in browser and change a page

Install PortBay and add your Inertia project

Homebrew installs the app and the bundled portbay CLI. PortBay identifies the Laravel family from composer.json plus artisan, checks composer.json for inertiajs/inertia-laravel before anything else in that family, then serves the app at its own .test hostname over trusted HTTPS with PHP-FPM running.

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 include the editor at all — it is not compiled in.

Settings › Account › Early Access

Start the project — your Vite server gets the stamping

PortBay launches the Vite dev server that compiles your page components, so it hands Vite a generated config that imports and spreads your own and adds a source-location plugin carried inside the app. The generated file lives in PortBay's data directory, never in your repo. Nothing is added to package.json or composer.json.

portbay start myapp

Open Edit in browser and change a page

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 your Inertia links and visits work normally. Switch to Edit, click an element in a page component, and the change is spliced into that exact span of the source file.

https://myapp.test/about
Without PortBay

Two halves, two lanes

An Inertia route passes through a Blade shell and lands in a page component. Both are editable; only one of them is precisely mapped, and it is the one you spend your time in.

A Vue or Svelte page gets one extra tier over a React one: those formats are markup-first, so component usages carry coordinates too. In a .jsx or .tsx page, markup produced by a component you did not author has none.

Questions

Asked before downloading

Because its pages are not Blade. An Inertia route renders a Vue, React or Svelte component compiled by Vite, and PortBay launches that dev server itself — so it can add source-location stamping from outside your repo, exactly as it does for any other Vite project. Blade renders on the server, where there is no such seam, which is why the other two lanes in the Laravel family behave differently.

No. Nothing goes into composer.json and nothing goes into package.json. The stamping plugin ships inside the PortBay app and reaches Vite through a generated config that imports and spreads your own, kept in PortBay's data directory. Uninstall PortBay and both manifests, your lockfiles and your vite.config are byte-for-byte what they were.

PortBay identifies the Laravel family from a composer.json plus an artisan file, then checks composer.json for inertiajs/inertia-laravel before checking anything else in that family. That order is deliberate: a project carrying both Inertia and Livewire is treated as Inertia, because that is the lane with the better capability rather than the one that happens to be alphabetically first.

Into the page component, not into a Blade view. PortBay resolves the route through routes/web.php to the Inertia page name the action passed — Inertia::render('About') gives About — then to the component file behind that name, and writes an Inertia Head element there. If the component has no Head yet, one is created and the import is added, rather than the field being reported as locked. Before that adapter existed, this entire lane refused Inertia projects.

In one respect, yes. .vue and .svelte are markup-first formats, so a component usage carries its own coordinate and an element rendered by one of your components still traces back to where you used it. .jsx and .tsx are script-first: host elements are stamped but component usages are not, because a capitalised tag there can be a TypeScript generic parameter list. The practical difference is markup produced by a library you did not author, which has no coordinate on a React page.

Yes, on the other lane. app.blade.php is a server-rendered template with no source stamping, so edits there are resolved by finding your markup in the file rather than by following a coordinate — which means text, class and attribute edits write, and structural edits are refused rather than guessed. In practice the shell is a handful of lines you rarely touch, and everything you do touch is in the page components.

No. It is a PortBay Pro feature, still in early access behind an opt-in toggle in Settings, and it is not compiled into the open-source build. It refuses to run while the project is shared over a public tunnel, and the edit bar works only on local .test hosts. Running an Inertia app on a real .test domain with trusted HTTPS, PHP-FPM and a managed database is in the free app.

Yes, on the page-component side. JSX, TSX and Vue are among the four formats where that structural edit is supported, so an element in a page component can be moved into a new component file, with the import added and the original span replaced by the tag. A span carrying a template expression is refused by name, because the values it uses are locals of the page and would not exist in the new file. The Blade shell does not get this: extraction is refused there rather than half-written, because a component means something different in a PHP template.

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