Visual editor

Editors see your real website next to the form, update it live while they type, and click blocks to edit them.

  1. In Settings → Preview, add your site's preview URL (e.g. https://www.example.com or http://localhost:4000).
  2. Mark blocks: spread editable(block) (React), v-editable (Vue) or use:editable (Svelte) on each block's root element.
  3. Use useLiveEntry / liveEntry for the page and useLiveGlobals / liveGlobals for getGlobals(), so unsaved changes show up immediately.
  4. Verify the editor ticket on your server and switch to draft content with a preview token:
import { verifyEditorTicket } from "@blokcms/client";

const editor = await verifyEditorTicket(request.url, process.env.BLOKCMS_PREVIEW_SECRET);
const client = editor
  ? blok.with({ token: PREVIEW_TOKEN, draft: !editor.release, release: editor.release ?? undefined })
  : blok;

The preview secret (Settings → Preview) signs short-lived tickets, so a leaked preview link stops working after a few minutes. The page runs inside an iframe: allow the admin origin in your frame-ancestors.

Globals

Globals (site settings, an announcement bar, the footer) have no page of their own: the editor previews them on a page you pick, the start page first. When your page reads them through useLiveGlobals (or useLiveEntry for a single getGlobal), they update while you type; otherwise the preview reloads after each save. Load globals in draft mode in the editor, like the page:

const [page, site] = await Promise.all([
  client.getEntryByPath(path, { include: ["*"] }),
  client.getGlobals(),   // every published global; drafts with a preview token
]);

Not using a framework? Load https://docs.blokcms.app/bridge/v1.js and call BlokBridge.initBridge({ onUpdate }).

Editing on the page

Clicking a block opens its fields, with the field you clicked focused. The selected block gets a toolbar: select its parent, move it, duplicate it, comment on it or delete it, and add a block before or after it with the + buttons. Drag its grip to move it, or drag a type from Add blocks onto the page; only places that take that type light up. Everything can be undone (⌘Z), also when someone else edits the same entry.

Two optional markers make this more precise. Without them, the editor finds the clicked field by its text.

<h1 {...editableField(block, "headline")}>{fields.headline}</h1>   // the click focuses Headline
<div {...editableList(block, "items")}>                              // an empty list shows "Add card"
  <Blocks blocks={fields.items} />
</div>

In Vue use v-bind="editableField(block, 'headline')"; in Svelte spread editableFieldAttrs(block, "headline") and editableListAttrs(block, "items"). Without a framework, set data-blok-field="<blockId>:<key>" and data-blok-list="<blockId>:<field>".

Clicks select blocks. To use accordions, tabs or forms in the preview, switch the toolbar to Interact, or hold Alt while clicking. Shortcuts work in the preview too: Esc selects the parent, Delete removes, ⌘D duplicates, Alt+↑/↓ moves, ⌘C/⌘V copy and paste blocks (also between entries), ⌘S saves.

Header and footer usually come from a global. Clicking them offers to edit that global on the same page. Report the roots of what you show by passing useLiveEntry/useLiveGlobals responses (they do this for you), or live: () => [{ id: entryId, root: content.id }] to initBridge.

Troubleshooting