useTypixEditor & TypixEditor
The hook that creates the editor, the instance it returns, and how to use both
useTypixEditor is the v2 entry point. It creates a TypixEditor
instance — a thin, typed wrapper around Lexical — and tears it down on
unmount.
import { useTypixEditor, defaultTheme } from "@typix-editor/react";
import { StarterKit } from "@typix-editor/extension-starter-kit";
const extensions = [StarterKit()];
function MyComponent() {
const editor = useTypixEditor({
extensions,
theme: defaultTheme,
namespace: "my-editor",
});
// editor is a TypixEditor (or null if immediatelyRender: false on first render)
}Options
extensions (required)
The list of extensions to register. Each item is either:
- A bare extension constructor:
StarterKit(),DragDropPasteExtension() - A configured tuple from
configExtension:configExtension(MentionExtension, { trigger: "@" })
Each extension augments the global TypixCommands<R> type, so
editor.chain() is fully typed for the extensions you've installed.
theme
CSS-class theme passed to Lexical. Use defaultTheme unless you have a
reason to override.
import { defaultTheme } from "@typix-editor/react";
theme: defaultTheme,namespace
Unique string identifying this editor instance. Required when multiple editors render on the same page.
namespace: "comment-editor-42",content
Initial content as serialized state (the shape editor.getJSON()
returns).
content: {
root: {
children: [/* … */],
direction: null,
format: "",
indent: 0,
type: "root",
version: 1,
},
},editable
true (default) or false. Read-only when false.
autofocus
"start", "end", true, or false. Defaults to false.
immediatelyRender
When false, defers editor creation until after the first render. Use
this for SSR safety. Add a null guard:
const editor = useTypixEditor({
extensions,
immediatelyRender: false,
});
if (!editor) return null;Lifecycle callbacks
All optional. Each receives an object with the editor instance.
| Callback | Fires when |
|---|---|
onBeforeCreate({ options }) | Before the editor is constructed; mutate options here. |
onCreate({ editor }) | Editor is ready to use. |
onUpdate({ editor }) | Content changed. |
onSelectionUpdate({ editor }) | Selection moved. |
onFocus({ editor }) | Editor got focus. |
onBlur({ editor }) | Editor lost focus. |
onDestroy() | Editor torn down. |
onError(error) | Lexical or extension threw. |
Each fires synchronously during Lexical's reconciliation. Heavy work (network, expensive serialization) should be debounced.
The TypixEditor instance
Fluent commands
editor.chain().toggleBold().toggleItalic().run();
editor.chain()
.focus()
.insertText("Hello")
.toggleBold()
.run();Each method returns the chain for further calls. .run() executes the
batched commands inside a single Lexical update — atomic.
can() checks
if (editor.can().toggleBold()) {
editor.chain().toggleBold().run();
}Same fluent API; returns booleans instead of executing.
Direct Lexical access
editor.lexical.dispatchCommand(SOME_LEXICAL_COMMAND, payload);
editor.lexical.update(() => {
const root = $getRoot();
// ...standard Lexical $-API
});editor.lexical is the underlying LexicalEditor. Use it for raw
Lexical APIs not yet exposed through editor.chain().
Serialization
const json = editor.getJSON(); // SerializedContent (load with setContent)
const html = editor.getHTML(); // string
const text = editor.getText(); // string
editor.setContent(json); // load from JSONState queries
editor.isEmpty(); // boolean
editor.isEditable(); // boolean
editor.setEditable(v); // toggle
editor.isDestroyed(); // true after unmountEvents
const off = editor.emitter.on("contentChange", () => {
console.log("content changed");
});
// Later:
off();Available events: contentChange, selectionChange, focus, blur,
create, destroy, transaction.
Identity
editor.id; // auto-generated unique id
editor.namespace; // the namespace you passedSharing across components
Wrap children in TypixEditorContext.Provider so they can access the
editor via useCurrentTypixEditor():
import { TypixEditorContext } from "@typix-editor/react";
return (
<TypixEditorContext.Provider value={{ editor }}>
<EditorToolbar />
<EditorContent editor={editor} placeholder="…" />
<FloatingLinkUI />
</TypixEditorContext.Provider>
);In any descendant:
import { useCurrentTypixEditor } from "@typix-editor/react";
function CustomButton() {
const editor = useCurrentTypixEditor();
return (
<button onClick={() => editor.chain().toggleBold().run()}>Bold</button>
);
}Reactive state in components
Use useEditorState to subscribe to a Lexical state value. Re-renders
only when the selector's value changes (deep equality by default).
import { useEditorState } from "@typix-editor/react";
function WordCount() {
const count = useEditorState((state) => state.read(() => $getRoot().getTextContent().split(/\s+/).length));
return <span>{count} words</span>;
}