Rafael Zasas
Rafael Zasas

Reputation: 993

How to use inline css with Lexical theme instead of class names

I am building an email client which uses lexical to convert the Rich Text into HTML using $generateHtmlFromNodes. I have specified the Tailwindcss class names in the lexical theme property of the initialConfig.

  const theme: EditorThemeClasses = {
    paragraph: 'text-base mb-1',
    center: 'text-center text-blue-200',
    list: {
      nested: {
        listitem: 'list-disc',
      },
      ol: 'list-decimal',
      ul: 'list-disc',
      listitem: 'list-inside',
    },
    text: {
      bold: 'font-bold',
      italic: 'italic',
      underline: 'underline',
      strikethrough: 'line-through',
      underlineStrikethrough: 'line-through underline',
    },
    link: 'text-blue-500 hover:text-blue-600',
    image: 'object-contain flex flex-row w-2/3 p-4 h-auto',
  };

  const initialConfig = {
    namespace: 'MyEditor',
    editable: true,
    nodes: [ImageNode, ListNode, ListItemNode],
    theme,
    onError(error) {
      throw error;
    },
  };

I am able to get fully renderable html with the correct class names, however when the email is sent, the CDN tag is either stripped from the email or does not convert the styles correctly.

Is there a way to prefer inline css over class names in either the Lexical initialConfig or when using $generateHtmlFromNodes?

Upvotes: 2

Views: 2059

Answers (1)

Giyu Tomioka
Giyu Tomioka

Reputation: 1

There is a dedicated page about Serialization & Deserialization of HTML

You can pass your custom export function in initial config and change the exported html element

 const initialConfig: InitialConfigType = {
    namespace: 'Rich-Text-Editor',
    theme,
    onError: (error) => console.error(error),
    nodes: [ListNode, ListItemNode],
    html: {
        export: htmlExportMap
    }
};

htmlExportMap.ts

import { ListNode, ListItemNode } from '@lexical/list';
import { DOMExportOutputMap, isHTMLElement, TextNode } from 'lexical';

export const htmlExportMap: DOMExportOutputMap = new Map();

// Text Node Export
htmlExportMap.set(TextNode, (editor, t) => {
    const target = t as TextNode;
    const node = target.exportDOM(editor);
    const { element } = node;

    if (isHTMLElement(element)) {
        if (target.hasFormat('bold')) {
            const el = element.querySelector('strong') ?? element;
            el.style.fontWeight = 'bold';
            el.removeAttribute('class');
        }
        if (target.hasFormat('italic')) {
            const el = element.querySelector('i') ?? element;
            el.style.fontStyle = 'italic';
            el.removeAttribute('class');
        }
        if (target.hasFormat('underline')) {
            const el = element.querySelector('u') ?? element;
            el.style.textDecorationLine = 'underline';
            el.removeAttribute('class');
        }
    }

    return node;
});

// List Node Export
htmlExportMap.set(ListNode, (editor, t) => {
    const target = t as ListNode;
    const node = target.exportDOM(editor);
    const { element } = node;

    if (isHTMLElement(element)) {
        const format = target.getListType();
        switch (format) {
            case 'bullet':
                element.style.listStyleType = 'disc';
                element.removeAttribute('class');
                break;
        }
    }

    return node;
});

// List Item Node Export
htmlExportMap.set(ListItemNode, (editor, t) => {
    const target = t as TextNode;
    const node = target.exportDOM(editor);
    const { element } = node;

    if (isHTMLElement(element)) {
        element.style.marginInline = '2rem';
        element.removeAttribute('class');
    }

    return node;
});

Without export function

<p dir="ltr">
    <u>
        <i>
            <b><strong class="font-bold italic underline" style="white-space: pre-wrap;">Hey there</strong></b>
        </i>
    </u>
</p>
<p><br /></p>
<ul class="list-disc">
    <li value="1" class="mx-8"><span style="white-space: pre-wrap;">List 1</span></li>
    <li value="2" class="mx-8"><span style="white-space: pre-wrap;">List 2</span></li>
    <li value="3" class="mx-8"><span style="white-space: pre-wrap;">List 3</span></li>
</ul>

With export function

<p dir="ltr">
    <u style="text-decoration-line: underline;">
        <i style="font-style: italic;">
            <b><strong style="white-space: pre-wrap; font-weight: bold; color: red;">hey there</strong></b>
        </i>
    </u>
</p>
<p dir="ltr"><br /></p>
<ul style="list-style-type: disc;">
    <li value="1" style="margin-inline: 2rem;"><span style="white-space: pre-wrap;">List 1</span></li>
    <li value="2" style="margin-inline: 2rem;"><span style="white-space: pre-wrap;">List 2</span></li>
    <li value="3" style="margin-inline: 2rem;"><span style="white-space: pre-wrap;">List 3</span></li>
</ul>

Upvotes: 0

Related Questions