lexical: Bug: $generateNodesFromDOM does not apply styles properly
When using $generateNodesFromDOM to convert HTML to Lexical, styles such as underline or align are not being applied.
In the case of HTML with styles that changes tag name such as bold(<strong>) or Italic(<em>), the style looks well when converted to lexical using $generateNodesFromDOM.
However, for HTML with styles that only add className(e.g.editor-text-*), such as underline or strikethrough, the styles don’t seem to be applied when converted to lexical.
I referenced the convert code(HTML -> Lexical - lexical doc).
Lexical version: 0.3.5
Steps To Reproduce
(* example HTML string - No style applied to text(STYLE TEST))
<div class="editor-input" contenteditable="true" spellcheck="true" data-lexical-editor="true" style="user-select: text; white-space: pre-wrap; word-break: break-word;" role="textbox"><p class="editor-paragraph ltr" dir="ltr"><span data-lexical-text="true">STYLE TEST</span></p></div>
case 1. bold
- Select bold - it is applied to
<strong>tag.
- When convert it to lexical based on the html string obtained in step 1 and insert it, the bold style is well as shown below.

case 2. underline
-
Select underline - The tagname is not changed(still
<span>) and onlyeditor-text-underlineis added to the classname.
The underline is also visible in the editor.

-
However, when convert it to lexical based on html obtained in step 1 and insert, converted without underline applied.

case 3. bold + italic
-
Select bold and italic. The tagname is
<strong>, and italics only apply toeditor-text-italicclassname.
-
However, when convert and insert it, only applied
bold(<strong>). (where is theeditor-text-italic? 😢 )
Considering the above cases, when converting html string to lexical, style or classname is ignored and it seems to be applied only based on tagname.
Link to code example: HTML -> Lexical
const LoadHtmlPlugin = ({htmlString}: Props) => {
const [editor] = useLexicalComposerContext();
useEffect(() => {
editor.update(() => {
const parser = new DOMParser();
const dom = parser.parseFromString(htmlString, 'text/html');
const nodes = $generateNodesFromDOM(editor, dom);
// Select the root
$getRoot().select();
// Insert them at a selection.
const selection = $getSelection() as RangeSelection;
selection.insertNodes(nodes);
});
}, [editor]);
return null;
};
The current behavior
$generateNodesFromDOM does not apply styles properly
The expected behavior
If $generateNodesFromDOM is used, the style and className of the dom must be maintained.
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Reactions: 34
- Comments: 16 (3 by maintainers)
This is the canonical way to do this.
I’ve implemented a patch-function that adds missed tag conversion (for Lexical@0.6.3:
sub,sup,s) andbackground-colorandcolorstyles transfer from the DOM node to the Lexical nodeUPD After some investigation I figured out that the way of determining of applied formats for the node wasn’t correct for each cases, so I found the another way and updated the code snippet above using this
I ran into similar problems as described here but found a few different fixes and improved a bit on what @byTimo did. First it wasnt clear to me that I had to add styling for the specific theme classes, a lot of patches weren’t necessary for me after that. (Note: I only had issues with underlining) Coloring and background-color weren’t working but I think that is intentional, so instead of patching I extended and override the TextNode like this:
the extende node:
I believe I have the same issue, and I do not believe it is just a styling concern.
It seems that $generateHtmlFromNodes correctly applies style classes to the HTML, for me it is something like this (snippet):
<span class="textUnderline">aaaa</span>However as far as i can tell $generateNodesFromDOM does not have any logic to apply this in reverse (take the class and generate an underline node). So in my case where I am saving the output of $generateHtmlFromNodes and then reloading it via $generateNodesFromDOM I lose some subset of my styling on reload
So I think what you are looking for is exportDOM/importDOM, see here: https://lexical.dev/docs/concepts/serialization#lexicalnodeexportdom
For built in nodes I don’t think think there is a great way to do this besides monkey patching, maybe I’m wrong, see this issue here: https://github.com/facebook/lexical/issues/1262
This is what I did for exportDOM for the build in TextNode:
For my use case importDOM is already set up to handle u elements, it was just not exporting that way, but not sure of your use case.
Has anybody figured out any work around for this? I’m running into the same issue where most of my styles are getting dropped from the conversion from HTML back into lexical nodes.
Actually these patches are just some kind of global monkey-patches, so you can call
applyHtmlToRichContentPatchessomewhere in the module where your rich editor component is declared.In my case, the patch is being called in the file with the Lexical editor configuration, but you can call it something like this
src/path/to/your/component/filename.ts
BTW, I’ve updated the code snippet above a bit. Please, take a look if you’re using this.
Is it just me or is
IS_UNDERLINEonly exported from the dev build and not the prod build? Lexical ships with aLexicalConstants.d.tsfile but no matching module. Storybook ends up complaining that it can’t findlexical/LexicalConstants, and runningrg IS_UNDERLINE node_modules/lexicalreturns the following:It looks like the solution from @pbrown-iris-construction works as long as I define
const IS_UNDERLINE = 1 << 3. It would be great to see Lexical support exporting underlines in HTML as a core feature.I think we are supposed to write styles for those classes.(I wrote styles for when I used this) It helps to apply multiple formatting to same text? instead of wrapping them inside different tags. In case you wanted properties being used inside the lexical playground here it is
strong and em are handled in the docs example: https://lexical.dev/docs/concepts/serialization#handling-extended-html-styling
I am facing styling issues as well.
I have styles applied to all the elements except
imgelement.When I resize the image in the editor and try to render the HTML generated by
$generateHtmlFromNodes, it overflows in x direction and none of the width, height are applied. I can see the values in editorState json but I don’t see that coveted in the HTML.I tried upgrading to the latest version. It didn’t fix. I have version
0.10.0right now.Please help!
–
Edit: NVM.
I just had to make the following update in
ImageNode.tsxI resolved this issue by saving the Editor State instead of
$generateNodesFromDOMand then usingsetEditorStateto load the editor.The
editorStatecontains all the styles such as the formatting and alignments, so there is no issue that the style is missing as before!getEditorState.setEditorState.