Data Flow
Saving
Collect content from all editors and persist it to your backend.
Handling Saves
When the user saves, Root collects content from every registered Data component and passes a Map to your onsave handler. Try the live
example to see the output.
Save Output Demo
Edit me then save
Change this text, then hit save to see the data structure your onsave handler receives.
<script lang="ts">
import * as Editable from 'editable-kit';
import type { EditorContent } from 'editable-kit';
// Each key in the Map matches the "key" prop on Editable.Data.
// Each value is a record of field names to EditorContent.
//
// EditorContent is one of:
// { type: 'text', content: ProseMirrorJSON }
// { type: 'image-src', src: string, alt: string }
// { type: 'image-blob', blob: Blob, alt: string }
async function handleSave(allData: Map<string, Record<string, EditorContent>>) {
const hero = allData.get('hero');
if (hero) {
const title = hero.title; // { type: 'text', content: ProseMirrorJSON }
const image = hero.image; // { type: 'image-src', src: string, alt } | { type: 'image-blob', blob: Blob, alt }
// Send to your API, save to IndexedDB, etc.
await fetch('/api/hero', {
method: 'POST',
body: JSON.stringify({ title: title.content })
});
}
}
</script>
<Editable.Root {editing} onsave={handleSave}>
...
</Editable.Root>Type Safety
Data is generic over your
data shape. The snippet selectors are type-checked — text('title') only compiles if title is a ProseMirrorJSON field, image('cover') only if cover is an ImageState.
import type { ProseMirrorJSON, ImageState } from 'editable-kit';
type HeroData = {
title: ProseMirrorJSON; // ← text('title') ✓, image('title') ✗
subtitle: ProseMirrorJSON; // ← multiline('subtitle') ✓
cover: ImageState; // ← image('cover') ✓, text('cover') ✗
};
// Utility types available:
// JSONKeys<T> — keys where value extends ProseMirrorJSON
// ImageKeys<T> — keys where value extends ImageState