Localess

Visual Editor

Preview and edit content in real time — see every change reflected instantly in your running application without leaving the Localess UI.

The Localess Visual Editor opens your frontend application inside an iframe alongside the content form. As you edit fields on the right, the changes are pushed to the preview on the left in real time. Clicking on any marked element in the preview jumps directly to the corresponding field in the form.

Visual Editor

How it works

  1. Localess renders your app inside an iframe in the left panel of the document editor.
  2. A small sync script loaded by your app opens a message channel to the Localess parent window.
  3. When a field changes in the form, Localess sends an input or change event through the channel.
  4. Your app receives the event, updates its local state, and re-renders — no page reload needed.
  5. Editable elements marked with data-ll-id and data-ll-schema attributes are highlighted so editors can click them to jump to the right field in the form.

The editor toolbar switches between Visual Editor — the preview beside the form — and Form Mode, the form alone.

Setup

Integrating the Visual Editor takes one step in Localess and three in your frontend application.

Step 1 — Add a preview environment

In Settings → Visual Editor, add one or more environments, each with a Name (e.g. Production, Development) and a URL. Editors pick the environment from the preview toolbar.

The editor loads URL + locale/ + fullSlug, leaving the locale segment out for the default locale — so end the URL with /: https://preview.example.com/ loads https://preview.example.com/blog/post.

The URL must be an absolute http:// or https:// URL on a different origin from the Localess admin app, or the preview shows Invalid preview URL. The preview runs in a sandboxed iframe, and messages are only exchanged with that origin — so a URL that redirects to another origin (for example, to www.) won't connect. Use the final address.

Step 2 — Load the sync script

The sync script must be loaded in the browser. Use the SDK helper or add the script tag manually.

Via @localess/client:

import { loadLocalessSync } from "@localess/client";

// Call once on the client side, e.g. in your root layout or app entry point
loadLocalessSync("https://my-localess.web.app");

Or manually in HTML:

<script
  id="localess-js-sync"
  type="text/javascript"
  async
  src="https://my-localess.web.app/scripts/sync-v1.js"
></script>

Replace https://my-localess.web.app with your Localess instance origin.

Framework-specific SDKs can load the script automatically. Set enableSync: true when registering the provider:

SDKOption
@localess/reactlocalessInit({ enableSync: true })
@localess/angularprovideLocaless({ enableSync: true })
@localess/vueapp.use(Localess, { enableSync: true })
@localess/nuxtlocaless: { enableSync: true } in nuxt.config.ts
@localess/sveltelocalessInit({ enableSync: true })
@localess/astrolocaless({ enableSync: true }) in astro.config.mjs

Step 3 — Mark editable elements

Add data-ll-id and data-ll-schema attributes to the root element of each content block so the Visual Editor can highlight and select it. Add data-ll-field to individual field elements for field-level selection.

Use the helper functions from @localess/client to set these attributes:

import { localessEditable, localessEditableField } from "@localess/client";

// Marks the block root as editable
// Returns: { 'data-ll-id': '...', 'data-ll-schema': '...' }
localessEditable(data)

// Marks a specific field as editable
// Returns: { 'data-ll-field': 'title' }
localessEditableField<MyPage>('title')

React example:

const HeroSection = ({ data, links }) => (
  <section {...localessEditable(data)}>
    <h1 {...localessEditableField<HeroSection>('title')}>{data.title}</h1>
    <p {...localessEditableField<HeroSection>('subtitle')}>{data.subtitle}</p>
  </section>
);

Vue example:

<template>
  <section v-bind="localessEditable(data)">
    <h1 v-bind="localessEditableField('title')">{{ data.title }}</h1>
  </section>
</template>

Svelte example:

<section {...localessEditable(data)}>
  <h1 {...localessEditableField('title')}>{data.title}</h1>
</section>

localessEditable and localessEditableField are no-ops outside the Visual Editor iframe — they return empty objects when the sync script is not active, so they are safe to use in production.


Step 4 — Subscribe to edit events

Listen for input and change events from window.localess and update your application state. Always guard the subscription with a browser check — window.localess only exists when the sync script is loaded inside the Visual Editor iframe.

import { isBrowser } from "@localess/client";

if (isBrowser() && window.localess) {
  window.localess.on(['input', 'change'], (event) => {
    if (event.type === 'input' || event.type === 'change') {
      // Replace your server-fetched content with the live editor data
      setPageData(event.data);
    }
  });
}

The input event fires whenever a field value changes — every keystroke — for a real-time preview. The change event fires when blocks are added, removed, duplicated or reordered, and once when the preview connects, carrying the current content. Subscribe to both: input alone misses structural edits and the initial content.

Events reference

EventWhen it firesPayload
inputWhenever a field value changes (every keystroke){ type: 'input', data: ContentData }
changeWhen blocks are added, removed, duplicated or reordered — and once when the preview connects, with the current content{ type: 'change', data: ContentData }
saveWhen the document is saved{ type: 'save' }
publishWhen the document is published{ type: 'publish' }
unpublishWhen the document is unpublished{ type: 'unpublish' }
pongHeartbeat response from the editor{ type: 'pong' }
enterSchemaEditor cursor enters a schema block{ type: 'enterSchema', id, schema, field? }
hoverSchemaEditor cursor hovers over a schema block{ type: 'hoverSchema', id, schema, field? }
leaveSchemaEditor cursor leaves a schema block{ type: 'leaveSchema' }

SDK integrations

Official SDKs provide built-in Visual Editor support with enableSync and helper utilities. For frameworks without a dedicated SDK, use @localess/client directly following the manual setup steps above.

FrameworkSDKGuide
TypeScript / Node@localess/clientTypeScript SDK
Angular@localess/angularAngular SDK
React / Next.js@localess/reactReact SDK
Nuxt@localess/nuxtNuxt SDK
Svelte / SvelteKit@localess/svelteSvelte SDK
Astro@localess/astroAstro SDK

On this page