I have created a custom node in Lexical called StyledParagraphNode that extends the ParagraphNode. It works perfectly in development mode, but when I build the project and try to use the custom editor, the node doesn’t seem to work as expected.
Here’s my custom node definition:
import {
ParagraphNode,
SerializedParagraphNode,
EditorConfig,
DOMConversionMap,
LexicalEditor,
DOMExportOutput,
} from "lexical";
type Style = { [key: string]: string };
interface SerializedStyledParagraphNode extends SerializedParagraphNode {
style?: Style;
}
class StyledParagraphNode extends ParagraphNode {
__style: Style | undefined;
constructor(key?: string, style?: Style) {
super(key);
this.__style = style;
}
static getType() {
return "p";
}
static importDOM(): DOMConversionMap | null {
return {
p: () => ({
conversion: convertStyledParagraph,
priority: 1,
}),
};
}
exportDOM(editor: LexicalEditor): DOMExportOutput {
const { element } = super.exportDOM(editor);
if (element) {
(element as HTMLElement).removeAttribute("class");
(element as HTMLElement).removeAttribute("dir");
if (this.__style) {
Object.assign((element as HTMLElement).style, this.__style);
}
}
return {
element,
};
}
static clone(node: StyledParagraphNode): StyledParagraphNode {
return new StyledParagraphNode(node.__key, node.__style);
}
createDOM(config: EditorConfig): HTMLElement {
const dom = super.createDOM(config);
if (this.__style) {
Object.assign(dom.style, this.__style);
}
return dom;
}
exportJSON(): SerializedStyledParagraphNode {
const json = {
...super.exportJSON(),
style: this.__style,
};
return json;
}
static importJSON(
serializedNode: SerializedStyledParagraphNode
): StyledParagraphNode {
const { style } = serializedNode;
return new StyledParagraphNode(undefined, style);
}
}
function convertStyledParagraph(domNode: HTMLElement): {
node: StyledParagraphNode;
} {
const style = domNode.getAttribute("style");
const styleObject = style ? parseStyleString(style) : undefined;
return { node: new StyledParagraphNode(undefined, styleObject) };
}
function parseStyleString(styleString: string): Style {
return styleString.split(";").reduce((styleObj: Style, styleProperty) => {
const [key, value] = styleProperty.split(":").map((item) => item.trim());
if (key && value) {
styleObj[key] = value;
}
return styleObj;
}, {});
}
export { StyledParagraphNode, type SerializedStyledParagraphNode };
And here’s how I set up my editor configuration:
const initialConfig = {
namespace: "MyCustomEditor",
onError: (error: Error) => {
console.error("Lexical Error:", error);
},
editorState: null,
nodes: [
HeadingNode,
ListNode,
ListItemNode,
QuoteNode,
AutoLinkNode,
LinkNode,
ImageNode,
StyledParagraphNode,
{
replace: ParagraphNode,
with: (node: ParagraphNode) => new StyledParagraphNode(node.__key),
withKlass: StyledParagraphNode,
},
],
};
`
**I then pass this config to the LexicalComposer:**
`<LexicalComposer initialConfig={initialConfig}>
{/* Other components */}
</LexicalComposer>
It works perfectly fine in development mode, but when I build the project and deploy it, the custom node seems to break. The editor doesn’t render the styled paragraphs correctly, and I don’t see any errors in the console.
Does anyone know why this might be happening or how to debug the issue? Any guidance on how to fix this after the build would be appreciated.
I tried the following steps:
-
**Custom Node Implementation: ** I implemented a custom StyledParagraphNode by extending the ParagraphNode from Lexical and adding support for inline styles.
-
Development Mode: In dev mode, everything worked as expected. The styled paragraph rendered correctly with the inline styles applied.
-
Build Mode: After building the project and deploying it, I expected the custom node to behave the same way it did in development mode—rendering paragraphs with their inline styles.
However, in the built version, the styled paragraphs either failed to render or displayed without styles. I didn’t receive any errors in the console, making it difficult to troubleshoot.