A Svelte 5 wrapper for the Unlayer email editor - drag & drop email template builder.
Demo: https://unlayer-svelte.iamdani.sh/
This repository is organized as a monorepo with two workspaces:
unlayer-svelte/
- The main SDK package (@unlayer/svelte
)example/
- Example application demonstrating SDK usage# Install dependencies for all workspaces
npm install
# Run the example app
npm run dev
# Build the SDK package
npm run build
# Build all workspaces
npm run build:all
npm install @unlayer/svelte
<script lang="ts">
import { UnlayerEditor } from '@unlayer/svelte';
import type { UnlayerEditorOptions } from '@unlayer/svelte';
let editorRef: any;
let isLoaded = false;
const handleReady = (editor: any) => {
isLoaded = true;
console.log('Editor is ready!', editor);
};
const exportHtml = () => {
if (editorRef && isLoaded) {
editorRef.exportHtml((data: any) => {
console.log('Exported HTML:', data.html);
console.log('Design JSON:', data.design);
});
}
};
const editorOptions: UnlayerEditorOptions = {
minHeight: '500px'
};
</script>
<UnlayerEditor
bind:this={editorRef}
options={{
...editorOptions,
onReady: handleReady
}}
/>
<button on:click={exportHtml} disabled={!isLoaded}>
Export HTML
</button>
design
(optional)object | null
null
tools
(optional)Record<string, any>
{}
options
(optional)UnlayerEditorOptions
{}
The options
prop accepts an UnlayerEditorOptions
object with the following properties:
minHeight
(optional)string
'100%'
onReady
(optional)(editor: UnlayerEditor) => void
onLoad
(optional)(editor: UnlayerEditor) => void
editorId
(optional)string
scriptUrl
(optional)string
options
(optional)object
tools
(optional)Record<string, any>
The component exposes the following methods via template ref:
loadDesign(design: object)
Load a design into the editor.
<script>
let editorRef;
const loadSampleDesign = () => {
const sampleDesign = { /* your design object */ };
editorRef.loadDesign(sampleDesign);
};
</script>
<UnlayerEditor bind:this={editorRef} />
exportHtml(callback?: (data: {html: string, design: object}) => void)
Export the current design as HTML.
<script>
let editorRef;
const exportDesign = () => {
editorRef.exportHtml((data) => {
console.log('HTML:', data.html);
console.log('Design:', data.design);
});
};
</script>
showPreview(device?: 'desktop' | 'mobile')
Show the preview mode.
<script>
const showPreview = () => {
editorRef.showPreview('desktop');
};
</script>
hidePreview()
Hide the preview mode.
<script>
const hidePreview = () => {
editorRef.hidePreview();
};
</script>
<script lang="ts">
import { UnlayerEditor } from '@unlayer/svelte';
import type { UnlayerEditorOptions } from '@unlayer/svelte';
let editorRef: any;
let isLoaded = false;
let htmlOutput = '';
let previewMode = false;
const handleReady = (editor: any) => {
isLoaded = true;
console.log('Editor ready!', editor);
};
const exportHtml = () => {
if (editorRef && isLoaded) {
editorRef.exportHtml((data: any) => {
htmlOutput = data.html;
});
}
};
const togglePreview = () => {
if (previewMode) {
editorRef.hidePreview();
} else {
editorRef.showPreview('desktop');
}
previewMode = !previewMode;
};
const loadSampleDesign = () => {
const sampleDesign = {
body: {
rows: [
{
cells: [1],
columns: [
{
contents: [
{
type: 'text',
values: {
text: 'Hello World!'
}
}
]
}
]
}
]
}
};
editorRef.loadDesign(sampleDesign);
};
const editorOptions: UnlayerEditorOptions = {
minHeight: '600px',
onReady: handleReady
};
</script>
<div class="editor-container">
<div class="toolbar">
<button on:click={loadSampleDesign} disabled={!isLoaded}>
Load Sample
</button>
<button on:click={togglePreview} disabled={!isLoaded}>
{previewMode ? 'Hide' : 'Show'} Preview
</button>
<button on:click={exportHtml} disabled={!isLoaded}>
Export HTML
</button>
</div>
<UnlayerEditor
bind:this={editorRef}
options={editorOptions}
/>
{#if htmlOutput}
<div class="html-output">
<h3>Exported HTML:</h3>
<pre>{htmlOutput}</pre>
</div>
{/if}
</div>
<style>
.editor-container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.toolbar {
margin-bottom: 20px;
display: flex;
gap: 10px;
}
.toolbar button {
padding: 8px 16px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.toolbar button:disabled {
background: #ccc;
cursor: not-allowed;
}
.html-output {
margin-top: 20px;
padding: 20px;
background: #f5f5f5;
border-radius: 4px;
}
.html-output pre {
max-height: 300px;
overflow-y: auto;
background: white;
padding: 10px;
border-radius: 4px;
}
</style>
This project uses npm workspaces. All commands should be run from the root directory:
# Install dependencies for all workspaces
npm install
# Run the example app (develops against local SDK)
npm run dev
# Build the SDK package
npm run build
# Run tests for the SDK
npm run test
# Lint all workspaces
npm run lint
# Format all workspaces
npm run format
# Type check all workspaces
npm run check
The SDK package can be published independently:
# Build and publish the SDK
npm run publish:sdk
# Update SDK version
npm run version:sdk patch|minor|major
# Run prepack for SDK
npm run prepack:sdk
You can also work with individual workspaces:
# Work in the SDK workspace
cd unlayer-svelte/
npm run dev
# Work in the example workspace
cd example/
npm run dev
The example app in example/
demonstrates how to use the SDK and serves as a development environment. It automatically uses the local SDK via the workspace dependency.
Apache-2.0
Contributions are welcome! Please feel free to submit a Pull Request.
If you encounter any issues, please file them on the GitHub issue tracker.