Skip to main content
Get up and running with Lexical quickly. This guide will walk you through creating your first text editor.

Installation

1

Install Lexical packages

Install the core Lexical package and React bindings:
npm install lexical @lexical/react
2

Create your editor component

Import the necessary components and create a basic editor.
3

Add plugins

Enhance your editor with plugins for history, error handling, and more.

Plain Text Editor

Here’s a minimal plain text editor:
import { LexicalComposer } from '@lexical/react/LexicalComposer';
import { PlainTextPlugin } from '@lexical/react/LexicalPlainTextPlugin';
import { ContentEditable } from '@lexical/react/LexicalContentEditable';
import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin';
import { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary';

const initialConfig = {
  namespace: 'MyEditor',
  onError: (error: Error) => console.error(error),
};

export default function Editor() {
  return (
    <LexicalComposer initialConfig={initialConfig}>
      <PlainTextPlugin
        contentEditable={<ContentEditable />}
        ErrorBoundary={LexicalErrorBoundary}
      />
      <HistoryPlugin />
    </LexicalComposer>
  );
}

Rich Text Editor

For a rich text editor with formatting capabilities:
import { LexicalComposer } from '@lexical/react/LexicalComposer';
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin';
import { ContentEditable } from '@lexical/react/LexicalContentEditable';
import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin';
import { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary';
import { HeadingNode, QuoteNode } from '@lexical/rich-text';
import { ListNode, ListItemNode } from '@lexical/list';
import { LinkNode } from '@lexical/link';

const initialConfig = {
  namespace: 'RichEditor',
  nodes: [HeadingNode, QuoteNode, ListNode, ListItemNode, LinkNode],
  onError: (error: Error) => console.error(error),
};

export default function RichEditor() {
  return (
    <LexicalComposer initialConfig={initialConfig}>
      <RichTextPlugin
        contentEditable={<ContentEditable />}
        ErrorBoundary={LexicalErrorBoundary}
      />
      <HistoryPlugin />
    </LexicalComposer>
  );
}

Vanilla JavaScript

You can also use Lexical without React:
import { createEditor } from 'lexical';
import { $getRoot, $createParagraphNode, $createTextNode } from 'lexical';

const editorElement = document.getElementById('editor');

const editor = createEditor({
  namespace: 'MyEditor',
  onError: (error) => console.error(error),
});

editor.setRootElement(editorElement);

// Initialize with content
editor.update(() => {
  const root = $getRoot();
  const paragraph = $createParagraphNode();
  const text = $createTextNode('Hello, Lexical!');
  paragraph.append(text);
  root.append(paragraph);
});

Reading and Updating State

Reading State

Use editor.read() to safely read the editor state:
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
import { $getRoot, $getSelection } from 'lexical';
import { useEffect } from 'react';

function MyPlugin() {
  const [editor] = useLexicalComposerContext();
  
  useEffect(() => {
    return editor.registerUpdateListener(({ editorState }) => {
      editorState.read(() => {
        const root = $getRoot();
        const selection = $getSelection();
        console.log('Root:', root);
        console.log('Selection:', selection);
      });
    });
  }, [editor]);
  
  return null;
}

Updating State

Use editor.update() to make changes:
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
import { $getRoot, $createParagraphNode, $createTextNode } from 'lexical';

function MyPlugin() {
  const [editor] = useLexicalComposerContext();
  
  const insertText = () => {
    editor.update(() => {
      const root = $getRoot();
      const paragraph = $createParagraphNode();
      const text = $createTextNode('Hello, Lexical!');
      paragraph.append(text);
      root.append(paragraph);
    });
  };
  
  return <button onClick={insertText}>Insert Text</button>;
}
Functions prefixed with $ (like $getRoot(), $createTextNode()) can only be called within editor.update() or editor.read() blocks.

Styling

Add CSS to style your editor:
.editor-container {
  margin: 20px auto;
  max-width: 800px;
  border: 1px solid #ddd;
  border-radius: 8px;
}

.editor-input {
  min-height: 200px;
  padding: 10px;
  font-size: 16px;
  outline: none;
}

Next Steps

Core Concepts

Understand Lexical’s architecture and design

React Plugins

Explore available plugins for lists, tables, links, and more

Create Custom Nodes

Learn how to create custom node types

Working with Commands

Implement custom commands and event handling

Build docs developers (and LLMs) love