Skip to content

Lexical is an extensible text editor framework that provides excellent reliability, accessibility and performance.

License

Notifications You must be signed in to change notification settings

atariandante/lexical

Repository files navigation

Lexical

Lexical is a fast, light-weight, extensible library for building rich text editors on the web.

The core of Lexical is a dependency-free text editor engine that allows for powerful, simple and complex, editor implementations to be built on top. Lexical's engine provides three main parts:

  • editor instances that each attach to a single content editable element.
  • a set of editor states that represent the current and pending states of the editor at any given time.
  • a DOM reconciler that takes a set of editor states, diffs the changes, and updates the DOM according to their state.

By design, the core of Lexical doesn't do anything else, such as listen for keyboard input or other events. Instead this logic can be wired up manually, or via a preshipped package. This ensures tight extensibilty and keeps code-sizes to a minimal – ensuring apps only pay the cost for what they actually import.

For React apps, Lexical has tight intergration with React 18+ via the optional lexical-react package. This package provides production-ready utility functions, helpers and React hooks that make it seemless to create text editors within React.

Getting started with React

Below is an example of a basic plain text editor using lexical and lexical-react (try it yourself).

import {useCallback} from 'react';
import useLexical from 'lexical-react/useLexical';
import useLexicalPlainText from 'lexical-react/useLexicalPlainText';

const editorConfig = {
  // When Lexical encounters an error, this is where
  // we can report/handle it.
  onError(error) {
    throw error;
  }
};

function Editor() {
  // Create an Lexical editor instance and also a ref
  // that we need to pass to our content editable.
  const [editor, contentEditableRef, showPlaceholder] = useLexical(
    editorConfig,
  );

  // Setup plain text entry event handlers.
  useLexicalPlainText(editor);

  // Our <div> content editable element with some basic styling.
  return (
    <div>
      <div
        ref={contentEditableRef}
        contentEditable={true}
        role="textbox"
        spellCheck={true}
        style={{
          lexical: 0,
          overflowWrap: 'break-word',
          padding: '10px',
          userSelect: 'text',
          whiteSpace: 'pre-wrap',
        }}
        tabIndex={0}
      />
      {showPlaceholder && (
        <div className="placeholder">Enter some plain text...</div>
      )}
    </div>
  );
}

Working with Lexical

This section covers how to use Lexical, independently of any framework or library. For those intending to use Lexical in their React applications, it's advisable to check out the source-code for the hooks that are shipped in lexical-react.

Creating an editor instance and using it

When you work with Lexical, you normally work with a single editor instance. An editor instance can be created from the lexical package and accepts an optional configuration object that allows for theming and the passing of context:

import {createEditor} from 'lexical';

const config = {
  onError(error) {
    throw error;
  },
  theme: {
    ...
  },
  context: {
    ...
  },
};

const editor = createEditor(config);

Once you have an editor instance, when ready, you can associate the editor instance with a content editable <div> element in your document:

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

editor.setRootElement(contentEditableElement);

If you want to clear the editor instance from the element, you can pass null. Alternatively, you can switch to another element if need be, just pass an alternative element reference to setRootElement.

Understanding Editor State

TODO

Updating an editor instance

There are two ways to update an editor instance, either with editor.update() or editor.setEditorState().

TODO

Contributing to Lexical

  1. Clone this repository

  2. Install dependencies

    • npm install
  3. Start local server and run tests

    • npm run start
    • npm run test
      • The server needs to be running for the e2e tests

Optional but recommended, use VSCode for development

  1. Download and install VSCode

    • Download from here (it’s recommended to use the unmodified version)
  2. Install extensions

    • Flow Language Support
      • Make sure to follow the setup steps in the README
    • Prettier
      • Set prettier as the default formatter in editor.defaultFormatter
      • Optional: set format on save editor.formatOnSave
    • ESlint

Documentation

Browser Support

  • Firefox 52+
  • Chrome 49+
  • Edge 79+ (when Edge switched to Chromium)
  • Safari 11+
  • iOS 11+ (Safari)
  • iPad OS 13+ (Safari)
  • Android Chrome 72+

Note: Lexical does not support Internet Explorer or legacy versions of Edge.

Contributing

  1. Create a new branch
    • git checkout -b my-new-branch
  2. Commit your changes
    • git commit -a -m 'Description of the changes'
      • There are many ways of doing this and this is just a suggestion
  3. Push your branch to GitHub
    • git push origin my-new-branch
  4. Go to the repository page in GitHub and click on "Compare & pull request"
    • The GitHub CLI allows you to skip the web interface for this step (and much more)

Running tests

  • npm run test-unit runs only unit tests.
  • npm run test-e2e:chromium runs only chromium e2e tests.
  • npm run debug-test-e2e:chromium runs only chromium e2e tests in head mode for debugging.
  • npm run test-e2e:firefox runs only firefox e2e tests.
  • npm run debug-test-e2e:firefox runs only firefox e2e tests in head mode for debugging.
  • npm run test-e2e:webkit runs only webkit e2e tests.
  • npm run debug-test-e2e:webkit runs only webkit e2e tests in head mode for debugging.

About

Lexical is an extensible text editor framework that provides excellent reliability, accessibility and performance.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 50.9%
  • TypeScript 40.8%
  • HTML 6.8%
  • CSS 1.2%
  • Other 0.3%