Svelte
Add a full image and design editor to a Svelte or SvelteKit app. Mount Polotno in a component, load and save designs, and export PNG or PDF.
How to add an image editor to a Svelte app?
Polotno is a React-based editor. You can use it in a Svelte or SvelteKit app by mounting it into a <div> from a Svelte component. Your users get the full visual editor with text, images, templates, layers and multi-page documents. Svelte keeps the rest of the page, and talks to the editor through its store.
You don't need JSX or a React plugin in your Svelte build. Polotno ships a function that mounts the whole editor for you.
1) Install dependencies
npm install polotno react react-domreact and react-dom are Polotno's peer dependencies. Your Svelte code never imports them.
2) Create the editor component
Create src/lib/Editor.svelte. It mounts the editor when the component mounts and removes it when the component is destroyed. Set VITE_POLOTNO_KEY in .env.local to your key from the Polotno cabinet, and add the origin you run on (for example http://localhost:5173) to the key's allowed domains.
<!-- src/lib/Editor.svelte -->
<script lang="ts">
import { onMount } from 'svelte';
import type { StoreType } from 'polotno/model/store';
import 'polotno/ui.css';
let { onReady }: { onReady?: (store: StoreType) => void } = $props();
let container: HTMLDivElement;
onMount(() => {
let app: { store: StoreType; destroy: () => void } | undefined;
let cancelled = false;
// Import in the browser only: the editor needs the DOM.
import('polotno').then(({ createPolotnoApp }) => {
if (cancelled) return;
app = createPolotnoApp({
container,
key: import.meta.env.VITE_POLOTNO_KEY,
showCredit: true,
sections: undefined, // all side panels
});
onReady?.(app.store);
});
return () => {
cancelled = true;
app?.destroy();
};
});
</script>
<div bind:this={container} class="editor"></div>
<style>
.editor {
flex: 1;
min-height: 0;
}
</style>The editor is imported inside onMount, so it only loads in the browser. That keeps SvelteKit's server-side rendering away from code that needs the DOM.
3) Use it on a page
The page keeps its own UI in Svelte: a live page count, Save, and PNG and PDF export.
<!-- src/routes/+page.svelte -->
<script lang="ts">
import Editor from '$lib/Editor.svelte';
import type { StoreType } from 'polotno/model/store';
const STORAGE_KEY = 'polotno-design';
let store = $state<StoreType>();
let pageCount = $state(0);
function onReady(s: StoreType) {
store = s;
// The editor starts with one empty page; replace it with the saved design.
const saved = localStorage.getItem(STORAGE_KEY);
if (saved) s.loadJSON(JSON.parse(saved));
pageCount = s.pages.length;
s.on('change', () => {
pageCount = s.pages.length;
});
}
function save() {
localStorage.setItem(STORAGE_KEY, JSON.stringify(store!.toJSON()));
}
</script>
<div class="app">
<header>
<span>Pages: {pageCount}</span>
<button onclick={save} disabled={!store}>Save</button>
<button onclick={() => store!.saveAsImage({ fileName: 'design.png' })} disabled={!store}>
Export PNG
</button>
<button onclick={() => store!.saveAsPDF({ fileName: 'design.pdf' })} disabled={!store}>
Export PDF
</button>
</header>
<Editor {onReady} />
</div>
<style>
.app {
display: flex;
flex-direction: column;
height: 100vh;
}
</style>In SvelteKit 3 projects the library alias is #lib instead of $lib. The examples use Svelte 5 runes. In Svelte 4, replace $props() with export let onReady and $state() with a plain let.
Core concepts
Loading and saving designs
store.toJSON() returns the whole design as plain JSON, and store.loadJSON(json) opens it again. Save the JSON to your backend from a SvelteKit form action or API route. See the Store API.
Exporting PNG and PDF
store.saveAsImage() and store.saveAsPDF() download the file in the browser. The first PDF export loads the PDF library, so it takes longer than the ones after it. To upload instead, store.toDataURL() and store.toPDFDataURL() return the file as a base64 data URL.
Reacting to editor changes
The store is a MobX store. To update Svelte state when the design changes, listen with store.on('change', ...) and copy what you need into a $state variable. See Reactivity and events.
Choosing panels
createPolotnoApp accepts sections, the list of side panels to show, for example ['templates', 'text', 'photos', 'upload', 'layers']. To build custom panels or change the toolbar, follow the non-React integration guide: you build your own editor bundle in React and mount it from Svelte the same way.
FAQ
Does it work with SvelteKit server-side rendering?
Yes, as long as the editor loads in the browser only. Importing polotno inside onMount, as above, does that. You can also set export const ssr = false in the editor route's +page.js.
Can I use Polotno as a Svelte WYSIWYG or visual editor for print?
Yes. Polotno is a visual editor for designs: social posts, flyers, cards, and print products with bleed and PDF export. It is not a rich text editor for page content.
Can I edit PDFs?
Polotno exports designs to PDF. To open an existing PDF as an editable design, use the @polotno/pdf-import package, currently in beta. See PDF import for what carries over.
Demo repository
See a complete working example with source code: https://github.com/polotno-project/polotno-svelte
The repository is a SvelteKit app with the editor component, a page that saves to localStorage and restores on reload, and PNG and PDF export.