Localess
SvelteKit

Getting Started

Use Localess in a SvelteKit app — server-side loading with a secret token, schema-driven rendering, and Visual Editor live sync.

Package: @localess/svelte

The @localess/svelte package is the official Svelte integration for the Localess headless CMS platform. It provides component mapping, rich text rendering, and Visual Editor synchronization support for Svelte applications. It's a rendering-only package — it never fetches content on its own — pair it with the localessClient factory it re-exports for that (see Content). Never import @localess/client directly in a Svelte project; everything it exposes that Svelte apps need comes through @localess/svelte.

⚠️ Security Notice: localessInit() must run synchronously during a component's own initialization (Svelte's setContext constraint — see Setup below), which in practice means it always runs in code that ships to the browser. Only ever pass a public, read-only token to localessInit() — never a secret token. Reserve secret tokens for server-only code that fetches content directly with localessClient (a SvelteKit +page.server.ts load() function, guaranteed by SvelteKit to never reach the client bundle) — see SSR with SvelteKit.

Requirements

  • Node.js >= 24.0.0
  • Svelte ^5.0.0

Installation

# npm
npm install @localess/svelte@latest svelte@latest

# yarn
yarn add @localess/svelte@latest svelte@latest

# pnpm
pnpm add @localess/svelte@latest svelte@latest

Setup

@localess/svelte ships as a single unified package — there's no /ssr, /rsc, or /vite export split like @localess/react. Call localessInit() once, synchronously, at the top of a root component's <script> block — typically +layout.svelte — to configure the client, register components, and optionally enable the Visual Editor:

<!-- +layout.svelte -->
<script lang="ts">
  import { localessInit } from '@localess/svelte';
  import type { Snippet } from 'svelte';

  import { Page, Header, Teaser, Footer } from '$lib/components/localess';

  let { children }: { children: Snippet } = $props();

  localessInit({
    origin: 'https://my-localess.web.app',
    spaceId: 'YOUR_SPACE_ID',
    token: 'YOUR_PUBLIC_TOKEN', // public — this call runs in the browser
    enableSync: true, // only meaningful inside the Localess Visual Editor iframe
    components: { Page, Header, Teaser, Footer },
  });
</script>

{@render children()}

localessInit() must run during the component's own initialization phase — not inside onMount() or an async load() function — because Svelte's setContext only works synchronously at that point.

Schema keys must match _schema exactly. The shorthand { Page, Header } above works because the components are named after the schemas. There's no normalization on this map, so if your CMS uses different casing, spell the keys out: { 'hero-section': HeroSection }.

Initialization Options

OptionTypeRequiredDefaultDescription
originstringYesFully qualified domain with protocol
spaceIdstringYesLocaless Space ID, found in Space settings
tokenstringYesLocaless API token — public only, see the Security Notice above
version'draft' | stringNo'published'Default content version
debugbooleanNofalseEnable debug logging
cacheTTLnumber | falseNo300Cache TTL in seconds. Set false to disable caching entirely
componentsRecord<string, Component>No{}Map of schema keys to Svelte components
fallbackComponentComponentNoComponent rendered when a schema key has no registered component
enableSyncbooleanNofalseLoad the Visual Editor sync script for live-editing support

Writing components

Components receive data, links, references, and assets as props via $props() — type them with LocalessSchemaProps<T>, the contract every registered component accepts (there's no base class to extend, unlike @localess/angular's SchemaComponent<T>). Always apply localessEditable/localessEditableField so the Visual Editor can highlight and select the block and its fields:

<script lang="ts">
  import { localessEditable, localessEditableField } from '@localess/svelte';
  import type { LocalessSchemaProps } from '@localess/svelte';
  import type { HeroSection } from '../.localess/localess';

  let { data, links, references }: LocalessSchemaProps<HeroSection> = $props();
</script>

<section use:localessEditable={data}>
  <h1 {...localessEditableField<HeroSection>('title')}>{data.title}</h1>
  <p {...localessEditableField<HeroSection>('subtitle')}>{data.subtitle}</p>
</section>

Pass links, references, and assets through the entire tree — nested <LocalessComponent>s need them.

Full Example — SvelteKit

@localess/svelte doesn't fetch content, so a real project splits into two halves: a server load() function that fetches with a secret token, and a client-initialized component tree that renders and (optionally) live-syncs with a public token.

Root layout — src/routes/+layout.svelte

<script lang="ts">
  import { localessInit } from '@localess/svelte';
  import type { Snippet } from 'svelte';

  import { Page, Button } from '$lib/components/localess';

  let { children }: { children: Snippet } = $props();

  localessInit({
    origin: 'https://my-localess.web.app',
    spaceId: 'YOUR_SPACE_ID',
    token: 'YOUR_PUBLIC_TOKEN',
    enableSync: true,
    components: { Page, Button },
  });
</script>

{@render children()}

Server load — src/routes/[...slug]/+page.server.ts

import { LocalessApiError, localessClient } from '@localess/svelte';
import { error } from '@sveltejs/kit';
import { LOCALESS_ORIGIN, LOCALESS_SPACE_ID, LOCALESS_TOKEN } from '$env/static/private';

import type { Page } from '../../shared/models/localess';
import type { PageServerLoad } from './$types';

export const load: PageServerLoad = async ({ params }) => {
  const client = localessClient({
    origin: LOCALESS_ORIGIN,
    spaceId: LOCALESS_SPACE_ID,
    token: LOCALESS_TOKEN, // secret — server-only
  });

  try {
    return { content: await client.getContentBySlug<Page>(params.slug || 'home') };
  } catch (err) {
    if (err instanceof LocalessApiError && err.status === 404) {
      error(404, `Content not found for slug "${params.slug}".`);
    }
    throw err;
  }
};

Page — src/routes/[...slug]/+page.svelte

<script lang="ts">
  import { LocalessDocument } from '@localess/svelte';

  import type { PageData } from './$types';

  let { data }: { data: PageData } = $props();
</script>

<LocalessDocument document={data.content} />

Components — src/lib/components/localess/Page.svelte

<script lang="ts">
  import { LocalessComponent, localessEditable, localessEditableField } from '@localess/svelte';

  import type { Page } from '../../../shared/models/localess';

  let { data }: { data: Page } = $props();
</script>

<main use:localessEditable={data}>
  <h1 {...localessEditableField<Page>('title')}>{data.title}</h1>
  {#each data.buttons ?? [] as button (button._id)}
    <LocalessComponent data={button} />
  {/each}
</main>

Playground: playgrounds/svelte-kit is a full working SvelteKit project built on this pattern.

AI Coding Agents

This package ships a SKILL.md file that provides AI coding agents (GitHub Copilot, Claude Code, Cursor, and others) with accurate, up-to-date APIs, patterns, and best practices.

Reference it from your project's AGENTS.md:

## Localess

@node_modules/@localess/svelte/SKILL.md

License

MIT

On this page