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'ssetContextconstraint — 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 tolocalessInit()— never a secret token. Reserve secret tokens for server-only code that fetches content directly withlocalessClient(a SvelteKit+page.server.tsload()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@latestSetup
@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
_schemaexactly. 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
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
origin | string | Yes | — | Fully qualified domain with protocol |
spaceId | string | Yes | — | Localess Space ID, found in Space settings |
token | string | Yes | — | Localess API token — public only, see the Security Notice above |
version | 'draft' | string | No | 'published' | Default content version |
debug | boolean | No | false | Enable debug logging |
cacheTTL | number | false | No | 300 | Cache TTL in seconds. Set false to disable caching entirely |
components | Record<string, Component> | No | {} | Map of schema keys to Svelte components |
fallbackComponent | Component | No | — | Component rendered when a schema key has no registered component |
enableSync | boolean | No | false | Load 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-kitis 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