Getting Started
Install opt-editor, create an editor store, and render the first structured editor.
reopt designUpdated
1. Install the package
@reopt-ai/opt-editor requires React 19 or newer as a peer dependency. It works without an extra styling library or external state manager.
# npm
npm install @reopt-ai/opt-editor
# bun
bun add @reopt-ai/opt-editorPeer dependencies:
| Package | Version |
|---|---|
| react | ^19.0.0 |
| react-dom | ^19.0.0 |
Import the editor stylesheet once from your application entrypoint:
import "@reopt-ai/opt-editor/styles.css";2. Render the first editor
Rendering an editor needs three pieces: create state with createEditorStore, provide context with EditorProvider, then render the Editor component.
"use client";
import { useMemo } from "react";
import {
Editor,
EditorProvider,
createEditorStore,
defaultCatalog,
} from "@reopt-ai/opt-editor";
import "@reopt-ai/opt-editor/styles.css";
export default function App() {
const store = useMemo(() => createEditorStore(), []);
return (
<EditorProvider store={store} catalog={defaultCatalog}>
<Editor store={store} catalog={defaultCatalog} mode="edit" />
</EditorProvider>
);
}| Mode | Use | Behavior |
|---|---|---|
| stream | Display AI-generated content | Read-only rendering with live NDJSON patch updates |
| edit | Let users edit content directly | contentEditable blocks, Markdown shortcuts, slash commands |
3. Provide initial content
Pass an EditorSpec into createEditorStore to seed the document. The spec has three top-level fields.
root- ordered IDs for top-level elementselements- a flat map of every element by IDversion- an optimistic concurrency version that increments on mutation
const store = createEditorStore({
root: ["h1", "p1"],
elements: {
h1: {
id: "h1",
type: "heading",
props: { text: "Hello", level: 1 },
},
p1: {
id: "p1",
type: "paragraph",
props: { text: "Welcome to **opt-editor**." },
},
},
version: 1,
});Why a flat map? AI streams can add elements without index shifts, RFC 6902 JSON Patch maps cleanly to updates, and any element can be reached in constant time.
4. Use edit mode
In mode="edit", users can modify the document directly.
- contentEditable - click a text block and write directly into the store-backed document
- Markdown shortcuts - type
#,>, or```at the start of a line to transform the block - Slash commands - type
/to insert heading, list, code, quote, divider, callout, table, and image blocks - Inline marks - render Markdown-like
**bold**,*italic*, and`code`as formatted inline content - Undo and redo - call
store.undo()andstore.redo()to move through history
// Markdown shortcuts at the start of a line
// "# " -> heading (level 1)
// "## " -> heading (level 2)
// "> " -> quote
// "```" -> code block
// "- " -> unordered list
// "1. " -> ordered list
// "---" -> divider
// Slash command examples
// "/" -> open the block type menu
// "/heading" -> insert a heading block
// "/table" -> insert a table block
// "/image" -> insert an image block5. Next steps
Once the first editor is running, continue with the deeper guides:
- Core Concepts - Flat Spec architecture, EditorStore API, catalog, and validation
- Block Type Reference - props, nesting rules, and rendering behavior for built-in blocks
- AI Integration - prompts, SSE streams, and the useEditorStream hook
- Streaming Protocol - NDJSON patch rules, StreamCompiler, retry, and resume behavior