HTML to Lexical Migration #7562
-
|
Hello Lexical community, I am working on a data migration process from an old database that contains a column with rich HTML content. My goal is to convert that HTML to Lexical compliant JSON to store it in a new database and render it later in a Lexical editor on the frontend. To do this, I created an API in Next.js (App Router) that runs on the server side. This API receives the HTML, converts it using createEditor + $generateNodesFromDOM + jsdom, and returns the result as JSON. However, the result is always: {
"lexical": {
"root": {
"children": [],
"direction": null,
"format": "",
"indent": 0,
"type": "root",
"version": 1
}
}
}I have verified that jsdom is working correctly and that the necessary nodes (ParagraphNode, TextNode, HeadingNode, etc.) are registered. I also added a namespace to the editor (as required in recent versions), but the result is still empty: // app/api/convert2lexical/route.ts
import { NextResponse } from "next/server";
import { createEditor, $getRoot } from "lexical";
import { $generateNodesFromDOM } from "@lexical/html";
import { JSDOM } from "jsdom";
import { ParagraphNode, TextNode } from "lexical";
import { HeadingNode, QuoteNode } from "@lexical/rich-text";
function convertHtmlToLexicalJSON(html: string) {
const editor = createEditor({
namespace: "my-editor",
nodes: [ParagraphNode, TextNode, HeadingNode, QuoteNode],
});
let result: any = null;
editor.update(() => {
const cleanHtml = html.replace(/<!--[\s\S]*?-->/g, "");
const dom = new JSDOM(cleanHtml);
const body = dom.window.document.body;
const nodes = $generateNodesFromDOM(editor, body);
const root = $getRoot();
root.clear();
root.append(...nodes);
result = editor.getEditorState().toJSON();
});
return result;
}
export async function POST(req: Request) {
try {
const { html } = await req.json();
if (typeof html !== "string" || html.trim() === "") {
return NextResponse.json(
{ error: 'El campo "html" es requerido y debe ser un string.' },
{ status: 400 }
);
}
const lexicalJson = convertHtmlToLexicalJSON(html);
return NextResponse.json({ lexical: lexicalJson });
} catch (error) {
console.error("Error al convertir HTML a Lexical JSON:", error);
return NextResponse.json(
{ error: "Error interno del servidor." },
{ status: 500 }
);
}
}I understand that certain Lexical operations only work in the context of the browser, which makes me think that the problem is related to the use of the editor outside the client. Is there an official or recommended way to convert HTML to Lexical state in a server environment (Node.js)? Or should this operation be performed exclusively on the client? I appreciate any guidance, experience or suggestions you can share. Thanks in advance. |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 4 replies
-
|
You need to get the editor state after the update. https://lexical.dev/docs/concepts/editor-state#synchronous-reconciliation-with-discrete-updates |
Beta Was this translation helpful? Give feedback.
-
|
Hard to say at a glance without a full runnable example including the input string. There’s probably something wrong with how you’re doing the update. |
Beta Was this translation helpful? Give feedback.
-
|
I think you forgot to actually commit any code, that is just a starter template. |
Beta Was this translation helpful? Give feedback.
-
|
This is the problem, you're passing the body when the API expects a document const body = dom.window.document.body;
const nodes = $generateNodesFromDOM(editor, body); |
Beta Was this translation helpful? Give feedback.
-
|
See also https://lexical.dev/docs/concepts/serialization#html---lexical |
Beta Was this translation helpful? Give feedback.

This is the problem, you're passing the body when the API expects a document