Lexical 0.24 with Vanilla JS: Getting started


Summary

Lexical is a modern JavaScript (JS) text editor framework designed for extensibility and high performance. They adopt reactive state model, which ensures optimized updates and predictable behavior, and also have nodes as flexible data model.

Lexical is an open source project and considered the successor of Draft.js. It is primarily developed by Meta, licensed under MIT. It is not restricted to React, but supports Vanilla JS, too. The flexibility enables us to integrate it with other JS libraries such as Svelte and Vue.

This post shows how to embed the editor in a Bun-powered Vite project handled by Vanilla JS.

Environment

  • Web Editor: Lexical 0.24
  • Builder / Bundler: Vite 6.1.0
  • JavaScript runtime: Bun 1.2.2
  • OS: CathyOS (Linux distribution)

Tutorial

1. Create a Vite project

First, run:

$ bun run create vite lexical-example

Some questions will be asked. Here are my responses as an example:

✔ Select a framework: › Vanilla
✔ Select a variant: › TypeScript

Scaffolding project in /(...)/lexical-example...

Done. Now run:

  cd lexical-example
  bun install
  bun run dev

Let’s come in:

$ cd lexical-example

$ bun install

2. Install the editor framework

Add the dependency:

$ bun add lexical

It printed out installed [email protected].

3. Embed it into app

Rewrite src/main.ts as below:

import { createEditor, LexicalEditor } from 'lexical'

document.querySelector<HTMLDivElement>('#app')!.innerHTML = `
  <div id="myeditor" contenteditable></div>
`

let editor: LexicalEditor

document.addEventListener('DOMContentLoaded', () => {
  const editorElement = document.getElementById('myeditor')
  editor = createEditor()
  editor.setRootElement(editorElement)
})

There are three points:

  • Prepare <div> which is contenteidtable.
  • Create LexicalEditor.
  • Set the <div> as root element in the editor.

4. Test it to fail

Open http://localhost:5173/ with your web browser. Typing in it must not bring any update…😂

lexical-01.png

5. Implement an actual editor

The reason around the failure is that there is LexicalEditor instance but are not any actual editors activated.

We can fix it by registering packages such as plain text editor. Optionally, history module useful to manage input history is also available.

$ bun add @lexical/plain-text @lexical/history

Edit src/main.ts as below:

  import { createEditor, LexicalEditor } from "lexical"
+ import { createEmptyHistoryState, registerHistory } from '@lexical/history'
+ import { registerPlainText } from '@lexical/plain-text'
  (...)
  document.addEventListener("DOMContentLoaded", () => {
    (...)
+   registerPlainText(editor)
+   registerHistory(editor, createEmptyHistoryState(), 300)
  })

Complete src/main.ts

import { createEditor, LexicalEditor } from "lexical"
import { createEmptyHistoryState, registerHistory } from '@lexical/history';
import { registerPlainText } from "@lexical/plain-text";

document.querySelector<HTMLDivElement>('#app')!.innerHTML = `
  <div id="myeditor" contenteditable></div>
`

let editor: LexicalEditor;

document.addEventListener("DOMContentLoaded", () => {
  const editorElement = document.getElementById("myeditor")
  editor = createEditor()
  editor.setRootElement(editorElement)
  registerPlainText(editor)
  registerHistory(editor, createEmptyHistoryState(), 300);
})

6. Test it to succeed

Now we can type to dive in !!!

lexical-02.png

Conclusion

Lexical is an open source text editor framework designed for speed, reliability, and flexibility. It enables developers to create not only plain text editors but also rich text or WYSIWYG editors with structured content, plugins, and collaborative features.

Happy development :)

Series

Web Editor
  1. Lexical 0.24 with Vanilla JS: Getting started

Comments or feedbacks are welcomed and appreciated.