A modular block editor experiment with single ContentEditable.
Built with Svelte 5 runes for fine-grained reactivity.
An experimental approach to building a block-based rich text editor using:
- Single ContentEditable (preserves browser behavior)
- Real block architecture (not just visual)
- Svelte 5 runes for reactive state management
Currently, it's a working prototype that can handle basic text editing with paragraphs, line breaks, and selection.
- β Basic text editing in paragraphs
- β Line breaks with Shift+Enter
- β Single block selection and navigation
- β Block hierarchy (Codex β Paragraph β Text/Linebreak)
- β Transaction system with automatic rollback
- β Strategy pattern for keyboard handling
- β Reactive coordinates (each block knows its position)
- β Debug panel to visualize structure
- π‘ Multi-block selection (detection works, operations buggy)
- π‘ Block deletion (single block OK, multi-block buggy)
- π‘ Focus management (works but uses retry pattern = code smell)
- π¦ Text styling (properties exist: bold, italic, etc. - no UI/shortcuts)
- π¦ History system (tracks transactions - no undo/redo)
- π¦ Preset system (MinimalPreset exists, not really configurable)
- β Copy/Paste
- β Undo/Redo (Ctrl+Z/Y)
- β Text formatting UI
- β Public API (getValue, setValue, etc.)
- β Touch/Mobile support
- β Lists, Headings, Tables, Images, etc.
- β Plugin system
- β Serialization (HTML, Markdown export)
npm install @aionbuilders/codeximport { Codex } from '@aionbuilders/codex';
import { Paragraph } from '@aionbuilders/codex/blocks';
// Create editor with initial content
const codex = new Codex({
in: Codex.data([
Paragraph.data("First paragraph\nwith linebreak"),
Paragraph.data("Second paragraph")
])
});
// Get the Svelte component
const Editor = codex.component;
// In your Svelte component:
// <Editor {codex} /><script>
import { Codex } from '@aionbuilders/codex';
import Debug from '@aionbuilders/codex/debug/Debug.svelte';
const codex = new Codex();
</script>
<div>
<Editor {codex} />
<Debug {codex} />
</div>That's it. That's all you can do right now.
The architecture is actually solid and the main reason this project has potential:
Codex (root)
βββ Paragraph (container)
βββ Text (leaf)
βββ Linebreak (leaf)
βββ Text (leaf)
class Block {
// Position tracking (reactive)
start = $derived(/* calculated */);
end = $derived(/* calculated */);
// Selection state (reactive)
selected = $derived(/* from selection API */);
// Hierarchy
parent // Parent block
before // Previous sibling
after // Next sibling
// Operations
prepareEdit() // Returns operations
prepareInsert() // Returns operations
prepareRemove() // Returns operations
}// All mutations go through transactions
codex.tx([
new TextEdition(block, { from: 0, to: 5, text: 'Hello' })
]).execute(); // Can rollback on errornew Strategy(
'multi-block-delete',
(codex, context) => /* can handle? */,
(codex, context) => /* handle it */
).tag('keydown', 'delete');- Clean separation between state (
.svelte.js) and UI (.svelte) - Reactive coordinates update automatically with Svelte 5 runes
- Event bubbling through block hierarchy
- Extensible via manifests and capabilities
- Focus retry pattern (up to 10
requestAnimationFrameretries) - Many $derived computations (performance unknown)
- Complex prepare/execute/apply pattern (maybe overengineered)
- Normalizations in effects (risk of infinite loops)
- Svelte 5.34+
- SvelteKit (for development)
- No other runtime dependencies
- Fix multi-block selection deletion
- Stabilize focus without retries
- Add copy/paste basic
- Add undo/redo
- Text styling with UI
- Basic public API
- Performance testing
- Serialization
- More block types
- Plugin system
- Mobile support
This is an experiment. If you're interested in the approach:
- Try it out and report what breaks (spoiler: lots)
- Fix bugs in multi-block selection (critical path)
- Add tests (there are none)
- Discuss architecture in issues
git clone https://github.com/aionbuilders/codex
cd codex
npm install
npm run dev # Starts dev serversrc/lib/
βββ states/ # Core logic (Svelte 5 runes)
β βββ codex.svelte.js
β βββ block.svelte.js
β βββ blocks/
β βββ paragraph.svelte.js
β βββ text.svelte.js
βββ components/ # Svelte components
βββ strategies/ # Event handlers
βββ utils/ # Helpers
The Vision (not reality yet):
- One editor that scales from textarea to Notion
- Modular enough to use anywhere
- Respects browser native behavior
Current Reality:
- Interesting architecture
- Basic editing works
- Lots of bugs
- No production use cases
- This is NOT production ready
- APIs will change completely
- Many basic features don't work
- No tests, no docs, no stability
- Copy/paste doesn't work at all
If you need a working editor today, use:
MIT Β© Killian Di Vincenzo