Skip to content

[RTE] Use PlateElement and PlateLeaf in RTE components for extensibility #3062

@cpoftea

Description

@cpoftea

Now

  • @epam/uui-editor builds Plate elements (paragraph, headings, list items, blockquote, marks, quote, etc.) as plain DOM elements (<p>, <h1>, <strong>, …) instead of PlateElement / PlateLeaf from @udecode/plate-common, a few examples:
    component: (props): JSX.Element => {
    const { attributes, children } = props;
    return <p { ...attributes }>{ children }</p>;
    },

    export function NotePluginBlock({ attributes, children, nodeProps }: PlateElementProps) {
    let style;
    if (nodeProps) {
    const { borderColor, backgroundColor } = nodeProps as NoteNodeProps;
    style = {
    borderColor,
    backgroundColor,
    };
    }
    return (
    <div { ...attributes } style={ style } className={ cx(css.wrapper) }>
    { children }
    </div>
    );
    }

    const Quote: PlatePluginComponent = function QuoteComponent(props) {
    return (
    <blockquote
    { ...props.attributes }
    className={ css.quote }
    >
    { props.children }
    </blockquote>
    );
    };
  • Custom plugins that follow Plate’s documented pattern 1 (e.g. inject.aboveComponent wrapping nodes in PlateElement, or marks with PlateLeaf) do not compose reliably with those defaults: refs, attributes, and the component tree diverge from what Plate expects.
  • Teams that need that extensibility (e.g. diff view, wrappers) must patch the published bundle (e.g. patch-package), which is fragile on every upgrade.
  • Plate’s own docs describe wrapping content with PlateElement / PlateLeaf and asChild so Slate gets the correct DOM props; uui-editor’s defaults are not aligned with that recommendation. 2

To Do

  • Refactor default block components to use PlateElement (asChild: true or as: 'div' where a wrapper is required).
  • Refactor default mark components to use PlateLeaf with asChild: true.
  • Import PlateLeaf from @udecode/plate-common where marks are defined.
  • Verify behavior with plugins that use inject.aboveComponent / similar (e.g. diff-style wrappers).

Describe the solution you'd like

  • Blocks: e.g. <PlateElement asChild {...props}><p>{children}</p></PlateElement> (and the same idea for headings, li, blockquote, iframe container, note, quote, separator, to-do row, default paragraph override, etc.).
  • Marks: e.g. <PlateLeaf asChild {...props}><strong>{children}</strong></PlateLeaf> for bold/italic/code/sup/underline.

This matches Plate’s documented component pattern and removes the need for consumers to patch uui-editor for standard extensibility.

Appendix

CodeSandbox example

Footnotes

  1. Custom Plugins — element/mark components and inject.aboveComponent assume a consistent Plate component tree.

  2. Plugin ComponentsPlateElement / PlateLeaf apply the right props as required by Slate; children must always be rendered.

Metadata

Metadata

Assignees

Labels

RTEuui-editor packageimprovementSomething that could be better

Type

No type

Projects

Status

Backlog

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions