Skip to content

Feature: Custom textFormatMode to choose how text formatting is applied #7956

@kettanaito

Description

@kettanaito

Description

I propose Lexical gave the user a choice in how they want the inline TextNode formatting to be applied.

Currently, inline formatting is applied via inline styles taken from editorConfig.theme[formatType]. This leads to HTML elements that look like this:

<strong class="font-bold italic" data-lexical-text="true">Content</strong>

Instead, I would like for the outputted HTML to resemble the final, valid HTML as close as possible:

<strong data-lexical-text="true"><em>Content</em></strong>

Considerations:

  • The parent element remains TextNode. Formatting (tag nesting) is applied to the inner children of that element whenever applied.
  • Make this behavior config-dependent:
createEditor({
  textFormatMode: 'inline' // default `'theme'` for backward compatibility
})

Impact

  • No impact on existing users since the behavior in question is opt-in and backward -compatible.
  • Improved HTML output and smaller gap between the runtime and the output editor states.

Maintainer impact

This becomes dependent on config.textFormatMode:

setTextThemeClassNames(innerTag, 0, format, innerDOM, textClassNames);

Preserve getElementInnerTag as-is:

function getElementInnerTag(node: TextNode, format: number): string {
if (format & IS_BOLD) {
return 'strong';
}
if (format & IS_ITALIC) {
return 'em';
}
return 'span';
}

Presently, it short-circuits due to early return for every format so you cannot get <strong><em> nesting in case text format has both IS_BOLD and IS_ITALIC.

This function will be used conditionally based on config.textFormatMode. If the mode is set to 'inline', instead the created dom for TextNode will be recursively wrapped in the HTML elements representing all the text formatting applied to the node.

Affected logic is here:

const outerTag = getElementOuterTag(this, format);
const innerTag = getElementInnerTag(this, format);

And here:

const prevOuterTag = getElementOuterTag(this, prevFormat);
const nextOuterTag = getElementOuterTag(this, nextFormat);
const prevInnerTag = getElementInnerTag(this, prevFormat);
const nextInnerTag = getElementInnerTag(this, nextFormat);

I don't mind the order of nesting to be fixed so TextNode can reliably produce outerTag but have nested innerTags.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementImprovement over existing feature

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions