Typix LogoTypix
Guides

Lexical Interop

Use the Lexical API directly alongside Typix

Typix is built on Lexical, and you always have full access to the underlying Lexical editor. This guide shows common patterns for using the Lexical API directly.

Accessing the Lexical editor

Via TypixEditor

const editor = useTypixEditor();
const lexical = editor.lexical; // LexicalEditor

Via Lexical's own hook

import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';

const [editor] = useLexicalComposerContext();

Reading editor state

Lexical requires state reads to happen inside editor.getEditorState().read():

const editor = useTypixEditor();

// Using Typix's convenience method
const text = editor.read(() => {
  const root = $getRoot();
  return root.getTextContent();
});

// Using Lexical directly
editor.lexical.getEditorState().read(() => {
  const selection = $getSelection();
  if ($isRangeSelection(selection)) {
    console.log('Selected text:', selection.getTextContent());
  }
});

Updating editor state

Lexical requires mutations to happen inside editor.update():

const editor = useTypixEditor();

// Using Typix
editor.update(() => {
  const root = $getRoot();
  const paragraph = $createParagraphNode();
  const text = $createTextNode('Hello from Lexical!');
  paragraph.append(text);
  root.append(paragraph);
});

// Using Lexical directly
editor.lexical.update(() => {
  // Same Lexical operations
});

Registering commands

import { COMMAND_PRIORITY_LOW, createCommand } from 'lexical';

const MY_CUSTOM_COMMAND = createCommand('MY_CUSTOM_COMMAND');

function MyPlugin() {
  const editor = useTypixEditor();

  useEffect(() => {
    return editor.lexical.registerCommand(
      MY_CUSTOM_COMMAND,
      (payload) => {
        console.log('Custom command received:', payload);
        return true;
      },
      COMMAND_PRIORITY_LOW
    );
  }, [editor]);

  return null;
}

// Dispatch the command
editor.lexical.dispatchCommand(MY_CUSTOM_COMMAND, { data: 'hello' });

Registering listeners

const editor = useTypixEditor();

useEffect(() => {
  // Listen for updates
  const unregister = editor.lexical.registerUpdateListener(({ editorState }) => {
    editorState.read(() => {
      // React to changes
    });
  });

  return unregister;
}, [editor]);

Using Lexical plugins

Lexical's React plugins work directly inside EditorRoot since it sets up a LexicalComposer:

import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin';
import { TabIndentationPlugin } from '@lexical/react/LexicalTabIndentationPlugin';
import { MarkdownShortcutPlugin } from '@lexical/react/LexicalMarkdownShortcutPlugin';

<EditorRoot>
  <EditorContent />
  <TabIndentationPlugin />
  <MarkdownShortcutPlugin />
</EditorRoot>

EditorRoot already includes HistoryPlugin, ListPlugin, and AutoFocusPlugin by default.

Re-exported Lexical utilities

For convenience, @typix-editor/react re-exports common Lexical utilities:

import {
  // Selection
  $getSelection,
  $isRangeSelection,
  $setBlocksType,

  // Node creation
  $createParagraphNode,
  $createHeadingNode,

  // Commands
  FORMAT_TEXT_COMMAND,

  // Node types
  HeadingNode,
  ParagraphNode,
  TextNode,
  ListNode,
  ListItemNode,
  LinkNode,
  AutoLinkNode,
  CodeNode,
  CodeHighlightNode,
  QuoteNode,
  TableNode,
  TableRowNode,
  TableCellNode,

  // Core types
  type LexicalNode,
  type LexicalEditor,
  type TextFormatType,
  type Klass,
} from '@typix-editor/react';

Node transforms

Register transforms that run whenever a specific node type is modified:

const editor = useTypixEditor();

useEffect(() => {
  return editor.lexical.registerNodeTransform(TextNode, (textNode) => {
    const text = textNode.getTextContent();
    // Auto-correct or transform text
    if (text.includes('teh')) {
      textNode.setTextContent(text.replace('teh', 'the'));
    }
  });
}, [editor]);

When to use Lexical vs Typix API

Use Typix APIUse Lexical API
Toggle formattingCustom node creation
Export/import contentRegister commands
Block type changesNode transforms
AlignmentSelection manipulation
Font sizeCustom plugins
Focus/blurLow-level DOM operations

On this page