Edit a website visually on localhost
Ändra hemsidan visuellt på localhost. Edit text directly, change button style and link, add or remove buttons, and replace images.
There are two ways to edit a hemsida you are building. One is the Snabbsite editor pointed at your machine: our canvas, your app inside it. The other is this one: no editor, no login, no network. Click editable content on your site while it runs locally. Your changes land in your own JSON files.
Release status: the implementation exists in the Site Kit source, but npm version
0.5.0has not yet been verified in a clean external project. Do not promise this setup to a client until that release check is complete.
Use this one when you are deep in code and want the words changed without leaving the browser tab you are already in. Use the other one when you want the full dock, the history and the publish button.
What it does
You run next dev. You click a heading and type directly in it. Click a button
to change its declared variant and link, or remove it. A removed button stays as
an add-button placeholder in development. Click a picture to replace it with a
safe local raster image under 1.5 MB. snabbsajt/content/pages/<page>.json
changes on disk, and your dev server reloads it like any other save.
It works on a plane. Nothing here talks to us.
Setting it up
Three small pieces, and you already have two of them.
1. Mark your fields
The same marking the editor's canvas uses, so you write it once:
import { sajtField } from "@snabbsajt/site-kit/local-overlay";
export function Hero({ id, heading }: { id: string; heading: string }) {
return <h1 {...sajtField(id, "heading")}>{heading}</h1>;
}Text saves when you click outside it. Enter creates a new line. Escape restores the old text.
For a full button control, declare a select, link and boolean field. Mark
the rendered button with both helpers:
import { sajtButton, sajtField } from "@snabbsajt/site-kit/local-overlay";
<a
href={cta_link.href}
{...sajtField(sectionId, "button_variant")}
{...sajtButton({ label: "cta", link: "cta_link", visible: "cta_visible" })}
>
{cta_visible ? cta : "Add button"}
</a>2. Mount direct editing
Framework-free, so it is a useEffect in a client component:
"use client";
import { useEffect } from "react";
import { mountLocalOverlay } from "@snabbsajt/site-kit/local-overlay";
import { library } from "@/snabbsajt/blocks";
export function LocalOverlay() {
useEffect(() => mountLocalOverlay({ library }).destroy, []);
return null;
}Render it in your root layout. In a production build it draws nothing at all, so there is no flag to remember and no branch to write.
3. Add the route that writes
// app/%5F%5Fsnabbsite/content/route.ts
import { createLocalContentHandler } from "@snabbsajt/site-kit/local-content";
import { library } from "@/snabbsajt/blocks";
const handler = createLocalContentHandler({ library });
export const GET = handler;
export const POST = handler;That is the whole setup. The route reads your snabbsajt/content directory and
writes one field at a time.
What you can change
Direct editing supports text and richtext. select and icon open a small
choice control beside the clicked item. An image opens a local file picker for
PNG, JPG, WebP, GIF or AVIF files under 1.5 MB.
Prompt for your coding agent
Copy this into an agent that has your Next.js project open. The same prompt,
interactive demo, manual guide and downloadable starter are prepared for
/redigera-hemsida-lokalt. That page stays unlisted until the required Site Kit
release has been verified from npm in a clean project.
Add Snabbsite local visual editing to this existing Next.js app. Keep the app in
this repository and keep its design. Do not import it into Snabbsite. Use the
exact Site Kit version named in the guide. Store editable values in
snabbsajt/content/pages/*.json and declare them with defineBlock plus
blockLibrary. Mark text and images with sajtField. Mark buttons with sajtField
plus sajtButton so I can edit text, style and link, remove them, and add them
again. Mount mountLocalOverlay from @snabbsajt/site-kit/local-overlay in a
client component and pass it the block library. Add the local-content route.
Keep all editing disabled in production. Run the app and test a text line
break, button style, button link, remove and add, and image replacement. Fix
errors you find.A list field cannot be changed here, and a write to one is refused. Reordering
a client's cards needs more controls than direct editing provides. Lists are
edited in the Snabbsite dashboard, where each card has Move up and Move down.
A field you marked locked is drawn greyed out and refused if something asks
for it anyway. It is your price line and your legal text, and direct editing is
not a way around that.
Local pictures are stored as data URLs in the page JSON. That is useful while building locally, but it is not a portable Snabbsite asset reference. Use the normal asset upload before pushing the content to Snabbsite.
What it never does
- It never publishes. Your client's hemsida is untouched.
- It never draws outside a development build. The editor returns an inert
handle, and the route answers
404, the same answer a route that does not exist gives. Two separate refusals are used because they fail differently. Leaked editing code could make text editable, and a leaked route could let a visitor write. - It never writes your code. Only the
propsof one block section in one page file. Never a component, never a config file, never the page's slug or id. - It never takes a filename from a request. The section is found by reading the pages directory, so nothing in a request can point at a file outside it.
- It has no history. Your editor's undo and
gitare the history. The write is atomic, so a crash mid-save leaves the old page intact.
When something is refused
The page shows the reason beside the edited item. The common ones:
| What it says | What happened |
|---|---|
"price" is locked by the block. | You marked the field locked in defineBlock. |
"tone" takes one of: light, dark. | A select only accepts the options you declared. |
"heading" is 41 characters, over its 40 limit. | The field's own maxLength. |
"cta" has an address that runs code. | A javascript: or data: link, however it is spelled. |
Block "hero" declares no "subtitle". | The key is not in your declaration. Add the field, restart, try again. |
No answer from the dev server. | The dev server restarted mid-keystroke. Type again. |
Hittade du inte svaret, eller stämmer något inte? Berätta det för oss.