richtext-core-svelte
v1.3.0
Published
[](https://www.npmjs.com/package/richtext-core-svelte) [](https://www.npmjs.com/package/richtext-core-svelte) [
Resources
- Docs — Full API reference and integration guides
- What is Eddyter? Why Developers Are Switching to This AI Editor (2026) — YouTube
- Integrate Eddyter in 30 Minutes Using AI Tools Cursor, Claude, Lovable — YouTube
Installation
npm install richtext-core-svelte
# or
yarn add richtext-core-svelte
# or
pnpm add richtext-core-svelteCompatibility
| Requirement | Version | |-------------|---------| | Svelte | 5.x | | Node.js | 16+ | | Browsers | Evergreen (Chrome, Edge, Firefox, Safari) |
The wrapper depends on
richtext-core-sdk, which bundles React + ReactDOM internally. Your Svelte app does not need to install or configure React.
Quick Start
1. Get your API key
- Create an account at eddyter.com
- Navigate to License Keys in your dashboard
- Copy your API key
2. Use the component
<script lang="ts">
import { Eddyter } from 'richtext-core-svelte';
const apiKey = import.meta.env.VITE_EDITOR_API_KEY as string;
let html = $state('<p>Start writing...</p>');
const currentUser = {
id: 'user-123',
name: 'John Doe',
email: '[email protected]',
avatar: 'https://example.com/avatar.jpg', // optional
};
</script>
<Eddyter
{apiKey}
value={html}
user={currentUser}
mentionUserList={['Alice', 'Bob', 'Charlie']}
onChange={(next) => (html = next)}
onReady={() => console.log('Editor ready!')}
onAuthError={(err) => console.error('Auth failed:', err)}
/>Styles are imported automatically by the wrapper — you don't need to import
richtext-core-sdk/style.cssmanually.
Features
Text & Formatting
- Bold, italic, underline, strikethrough, subscript, superscript
- Text color and background highlight with color picker
- 20+ font families with adjustable font sizes
- Text alignment (left, center, right, justify)
- Line height and letter spacing controls
Lists & Structure
- Bullet lists, numbered lists (decimal, alpha, roman)
- Interactive checklists with strikethrough
- Headings (H1-H6), blockquotes
- Horizontal rules
Tables
- Insert/delete rows and columns, merge cells
- Drag-to-resize columns and rows
- Header row styling, row striping
- Right-click context menu for table actions
Media
- Image upload with drag-drop and 8-point resize handles
- Video embed with drag-drop and paste support
- File attachments (downloadable files)
- Link insertion with floating editor
- Automatic link preview on hover
- Rich embeds for external content (YouTube, etc.)
AI Features (Premium)
- AI Chat assistant for content help
- Smart autocomplete (AI-powered text suggestions)
- Real-time grammar check and corrections
- Text enhancement (improve, shorten, expand)
- Tone adjustment (formal, casual, professional)
- AI image generation from text prompts
Advanced
- Slash commands (
/for quick formatting) - @Mentions with customizable user list
- Inline comments with bubble UI and sidebar
- Note panels (info, warning, error, success)
- Code blocks with syntax highlighting
- Interactive charts
- Digital signature capture
- Voice input / transcription
- Export to PDF
- HTML view toggle
- Drag-and-drop block reordering
- Markdown shortcuts
Dark Mode
The editor automatically detects your app's theme:
- Checks for
darkclass on<html>or<body> - Falls back to
prefers-color-scheme: darksystem preference - Or pass
darkMode={true}/darkMode={false}explicitly — changes apply at runtime without remounting.
<script lang="ts">
import { Eddyter } from 'richtext-core-svelte';
let isDark = $state(false);
</script>
<Eddyter apiKey="your-api-key" darkMode={isDark} />Preview Mode
Display saved editor content in read-only mode with interactive features:
<Eddyter
apiKey="your-api-key"
mode="preview"
value={savedHtml}
containerClass="my-preview-styles"
onPreviewClick={switchToEditMode}
/>API Reference
<Eddyter>
The main editor component.
Props
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| apiKey | string | Yes | Your Eddyter license key |
| value | string | No | Initial HTML content. Listen to onChange for updates |
| user | EddyterCurrentUser | No | Current user for comments / mentions. Defaults to anonymous |
| mode | 'edit' \| 'preview' | No | Editor mode (default: 'edit') |
| darkMode | boolean | No | true/false. Omit to auto-detect host's .dark class |
| customVerifyKey | (key: string) => Promise<EddyterApiResponse> | No | Use your own backend to validate the API key |
| mentionUserList | string[] | No | Names that appear in @mention suggestions |
| defaultFontFamilies | string[] | No | Font family names for the font selector |
| className | string | No | CSS class applied to the outermost editor wrapper |
| containerClass | string | No | CSS class applied to the preview container (only used when mode: 'preview') |
| contentClass | string | No | CSS class applied to the editable content area |
| floatingToolbarClass | string | No | CSS class applied to the floating toolbar and its portal container |
| style | Record<string, string \| number> | No | Inline style object applied to the wrapper |
| toolbar | EddyterToolbarConfig | No | Toolbar behavior (default: { mode: 'sticky', offset: 20, zIndex: 1000 }) |
| editor | EddyterEditorOptions | No | Editor container options (maxHeight) |
| enableReactNativeBridge | boolean | No | Force-enable RN WebView bridge messaging |
Callback Props
Svelte 5 uses callback props instead of event dispatching:
| Prop | Type | Fires when |
|------|------|------------|
| onChange | (html: string) => void | Editor content changes (debounced) |
| onReady | () => void | Editor finished mounting and authenticated |
| onAuthSuccess | () => void | API key validated successfully |
| onAuthError | (error: string) => void | API key validation failed |
| onFocus | () => void | Editor gained focus (React Native bridge) |
| onBlur | () => void | Editor lost focus (React Native bridge) |
| onHeightChange | (height: number) => void | Editor content height changes (React Native bridge) |
| onPreviewClick | () => void | User clicks anywhere inside the preview (e.g. to open edit mode) |
Exposed Methods (via bind:this)
interface ExposedApi {
/** Returns the underlying SDK instance (or null before mount) */
getInstance(): EddyterInstance | null;
}<script lang="ts">
import { Eddyter } from 'richtext-core-svelte';
let editor: Eddyter;
function toggleDarkMode() {
editor.getInstance()?.update({ darkMode: true });
}
</script>
<Eddyter bind:this={editor} apiKey="your-api-key" />
<button onclick={toggleDarkMode}>Dark mode</button>Supporting Types
import type {
EddyterInstance,
EddyterCurrentUser,
EddyterToolbarConfig,
EddyterEditorOptions,
EddyterApiResponse,
} from 'richtext-core-sdk';
interface EddyterCurrentUser {
id: string;
name: string;
email?: string;
avatar?: string;
}
interface EddyterApiResponse {
success: boolean;
message: string;
data?: unknown;
}
interface EddyterToolbarConfig {
mode?: 'sticky' | 'static';
offset?: number;
zIndex?: number;
}
interface EddyterEditorOptions {
maxHeight?: string | number;
}Toolbar Configuration
<Eddyter
apiKey="your-api-key"
toolbar={{ mode: 'sticky', offset: 64, zIndex: 1200 }}
/>Modes:
mode: 'sticky'-> toolbar detaches/sticks while scrolling and appliesoffset+zIndexmode: 'static'-> toolbar stays attached and ignoresoffset+zIndexeven if provided
Defaults: { mode: 'sticky', offset: 20, zIndex: 1000 }.
In static mode, if you want only the editor content area to scroll, pass a maxHeight using editor:
<Eddyter
apiKey="your-api-key"
toolbar={{ mode: 'static' }}
editor={{ maxHeight: 600 }}
/>Examples
Basic Editor
<script lang="ts">
import { Eddyter } from 'richtext-core-svelte';
</script>
<Eddyter apiKey="your-api-key" onReady={() => console.log('Ready!')} />Editor with State Management & Save
<script lang="ts">
import { Eddyter } from 'richtext-core-svelte';
let html = $state('<p>Start writing...</p>');
async function handleSave() {
await fetch('/api/save', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ content: html }),
});
}
</script>
<Eddyter apiKey="your-api-key" value={html} onChange={(next) => (html = next)} />
<button onclick={handleSave}>Save</button>Comments & Mentions
<script lang="ts">
import { Eddyter } from 'richtext-core-svelte';
const currentUser = {
id: 'u-1',
name: 'Jane Doe',
email: '[email protected]',
};
</script>
<Eddyter
apiKey="your-api-key"
user={currentUser}
mentionUserList={['Alice', 'Bob', 'Charlie']}
/>Custom API Key Verification
<script lang="ts">
import { Eddyter } from 'richtext-core-svelte';
async function customVerifyKey(apiKey: string) {
try {
const res = await fetch('/api/verify-key', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ apiKey }),
});
const data = await res.json();
return { success: data.valid, message: data.message || 'Verified' };
} catch {
return { success: false, message: 'Verification failed' };
}
}
</script>
<Eddyter apiKey="your-api-key" {customVerifyKey} />Theme Toggle Without Remount
<script lang="ts">
import { Eddyter } from 'richtext-core-svelte';
let isDark = $state(false);
</script>
<button onclick={() => (isDark = !isDark)}>Toggle theme</button>
<Eddyter apiKey="your-api-key" darkMode={isDark} />Static Toolbar with Scrollable Content
<Eddyter
apiKey="your-api-key"
toolbar={{ mode: 'static' }}
editor={{ maxHeight: '420px' }}
/>Migration
If you are upgrading from an earlier release, two legacy props were removed because they targeted SDK options that never reached the underlying editor:
| Old prop | New prop | Status |
|----------|----------|--------|
| previewClass | containerClass | Removed — old value was a no-op |
| editorClass | contentClass | Removed — old value was a no-op |
| — | floatingToolbarClass | New — style the floating toolbar / portal |
- <Eddyter apiKey={key} previewClass="p" editorClass="c" />
+ <Eddyter apiKey={key} containerClass="p" contentClass="c" />Troubleshooting
| Symptom | Fix |
|---------|-----|
| Editor renders but toolbars look broken | Make sure your bundler isn't tree-shaking richtext-core-sdk/style.css. The wrapper imports it automatically. |
| Theme does not switch | Bind darkMode={isDark} — it updates the editor without remounting. |
| API key errors | Confirm the key in your env vars and check the network tab for the verification request. |
| Content updates don't reach parent state | Pass an onChange callback and update your $state from there. |
License
Eddyter is proprietary software.
- Free for evaluation and non-commercial use
- Commercial use requires a paid license
- SaaS, redistribution, and competing products are prohibited without permission
For commercial licensing, visit eddyter.com
