Rupinderpal Thind
Rupinderpal Thind

Reputation: 537

How we can get html from editorState in Lexical rich editor?

I want to generate HTML format from editorState in Lexical Rich Editor, I'm able to get selection with editorState and what will be best to save into database, HTML or some sort of JSON format?

and I want to show this HTML outside of editor. here is some example of code

const onChange = (editorState) => {
  const editorStateTextString = editorState.read(() => {
    const selection = $getSelection();
    
    console.log(selection);

    return $getRoot().getTextContent();
  });

  // TODO: saving text only at the moment
  if (changeHandler) {
    changeHandler(editorStateTextString);
  }
};

<LexicalComposer initialConfig={editorConfig}>
  <div className="editor-container">
    <ToolbarPlugin aditionalTools={aditionalTools} />
    <div className="editor-inner">
      <RichTextPlugin
        contentEditable={<ContentEditable className="editor-input" />}
        placeholder={<Placeholder placeholder={placeholder} />}
      />
      <OnChangePlugin ignoreInitialChange onChange={onChange} />
    </div>
  </div>
</LexicalComposer>

Upvotes: 13

Views: 7196

Answers (5)

maja
maja

Reputation: 799

To build on Steve2955's answer, another possible implemention of the onChange functionality is to use the registerTextContentListener method of the editor instance:

useEffect(() => {
  ...
  editor.registerTextContentListener((text) => {
    editor.read(() => {
      console.log(text, $generateHtmlFromNodes(editor));
    });
  });
}, [editor]);

Upvotes: 0

Biswajit
Biswajit

Reputation: 1037

<OnChangePlugin onChange={(editorState, editor) => {
  editorState.read(() => {
     const html = $generateHtmlFromNodes(editor);
     console.log(html);
   });
}} />

This will console html

Upvotes: 4

ZetiX
ZetiX

Reputation: 1

You can grab editor from initialConfig using the editorState key.

const initialConfig = {
  editorState: (editor) => {
    editor.update(() => {
      const parser = new DOMParser();
      const dom = parser.parseFromString(htmlString, ‘text/html’);
      const nodes = $generateNodesFromDOM(editor, dom);
      $insertNodes(nodes);
    }):
  }
}

Then just pass initialConfig to LexicalComposer.

Upvotes: 0

Steve2955
Steve2955

Reputation: 680

I have been running into the same issue and solved it by using the following simple plugin. The hard part was getting a reference to the editor, which is what I used useLexicalComposerContext() for.

import { useState, useEffect } from "react";
import { OnChangePlugin } from "@lexical/react/LexicalOnChangePlugin";
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
import { $generateHtmlFromNodes, $generateNodesFromDOM } from "@lexical/html";
import { $insertNodes } from "lexical";

interface Props {
    initialHtml?: string;
    onHtmlChanged: (html: string) => void;
}

const HtmlPlugin = ({ initialHtml, onHtmlChanged }: Props) => {
    const [editor] = useLexicalComposerContext();

    const [isFirstRender, setIsFirstRender] = useState(true);

    useEffect(() => {
        if (!initialHtml || !isFirstRender) return;

        setIsFirstRender(false);

        editor.update(() => {
            const parser = new DOMParser();
            const dom = parser.parseFromString(initialHtml, "text/html");
            const nodes = $generateNodesFromDOM(editor, dom);
            $insertNodes(nodes);
        });
    }, []);

    return (
        <OnChangePlugin
            onChange={(editorState) => {
                editorState.read(() => {
                    onHtmlChanged($generateHtmlFromNodes(editor));
                });
            }}
        />
    );
};

export default HtmlPlugin;

You can use it in your LexicalComposer like so:

<LexicalComposer initialConfig={editorConfig}>
  <div className="editor-container">
    <ToolbarPlugin aditionalTools={aditionalTools} />
    <div className="editor-inner">
      <RichTextPlugin
        contentEditable={<ContentEditable className="editor-input" />}
        placeholder={<Placeholder placeholder={placeholder} />}
      />
      {/* see here */}
      <HtmlPlugin
        onHtmlChanged={(html) => console.log(html)}
        initialHtml="<h1>Test</h1><p>Lorem ipsum dolor sit amet</p>"
        />
    </div>
  </div>
</LexicalComposer>

Upvotes: 15

Alexandru Pavaloi
Alexandru Pavaloi

Reputation: 29

You should definitely save the JSON into the database. The most important thing is that this let's you decide how to render it. Maybe in some cases you want to render to HTML, but in others (eg: mobile) you want to render to native elements.

To get the JSON structure you can do:

editor.getEditorState().toJSON();

Also, regarding your second question. Here's how you can get the HTML:

import {$generateHtmlFromNodes} from '@lexical/html';

...    

const htmlString = $generateHtmlFromNodes(editor, null);

NOTE: you need to call the above method inside the Lexical context (ie: inside a callback like editor.update

Upvotes: 1

Related Questions