Major Releases

This page only covers major breaking changes. For patch and minor changes, refer to the individual package CHANGELOG.md files or visit the GitHub Releases page.

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

49.0.0

[email protected]

  • #4327 by @zbeyens
    • Renamed package to platejs:
      • Replace all @udecode/plate/react with platejs/react
      • Replace all '@udecode/plate' with 'platejs'

@platejs/[email protected]

  • #4327 by @zbeyens

    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.
  • #4327 by @zbeyens

    • Replaced editor.api.shouldMergeNodesRemovePrevNode with editor.api.shouldMergeNodes. shouldMergeNodes is now controlling the remove + merge behavior

      • Returns true if the default merging behavior should be applied.
      • Returns false if the default merging behavior should not be applied. This is used by Plate to prevent void blocks deletion, and to prioritize empty block deletion over merging.
      // Before
      editor.api.shouldMergeNodesRemovePrevNode(prev, current);
       
      // After
      editor.api.shouldMergeNodes(prev, current);
    • Replace editor.api.fragment option structuralTypes with unwrap.

      // Before
      editor.api.fragment(editor.selection, { structuralTypes: ['table'] });
       
      // After
      editor.api.fragment(editor.selection, { unwrap: ['table'] });

Minor Changes

  • #4327 by @zbeyens
    • editor.tf.insertSoftBreak now inserts a soft break instead of a hard break.

@platejs/[email protected]

  • #4327 by @zbeyens

    • editor.getType() now takes a pluginKey: string instead of a plugin: PlatePlugin instance.
      • Example: Use editor.getType(ParagraphPlugin.key) instead of editor.getType(ParagraphPlugin).
    • Plugins without a key property will not be registered into the editor.
    • Passing disabled: true prop to PlateContent will now also set the editor to readOnly: true state internally.
    • Editor DOM state properties have been moved under editor.dom namespace:
      • editor.currentKeyboardEvent is now editor.dom.currentKeyboardEvent.
      • editor.prevSelection is now editor.dom.prevSelection.
    • Editor metadata properties have been moved under editor.meta namespace:
      • editor.isFallback is now editor.meta.isFallback
      • editor.key is now editor.meta.key
      • editor.pluginList is now editor.meta.pluginList
      • editor.shortcuts is now editor.meta.shortcuts
      • editor.uid is now editor.meta.uid
    • NodeIdPlugin is now enabled by default as part of the core plugins. This automatically assigns unique IDs to block nodes.
      • Migration: If you were not previously using NodeIdPlugin and wish to maintain the old behavior (no automatic IDs), explicitly disable it in your editor configuration:
        const editor = usePlateEditor({
          // ...other options
          nodeId: false, // Disables automatic node ID generation
        });
    • The components prop has been removed from serializeHtml and PlateStatic.
      • Migration: Pass the components to createSlateEditor({ components }) or the individual plugins instead.
    • Plugin Shortcuts System Changes:
      • Shortcut keys defined in editor.shortcuts are now namespaced by the plugin key (e.g., code.toggle for CodePlugin).
      • The priority property for shortcuts is used to resolve conflicts when multiple shortcuts share the exact same key combination, not for overriding shortcuts by name.
      • preventDefault for plugin shortcuts now defaults to true, unless the handler returns false (i.e. not handled). This means browser default actions for these key combinations will be prevented unless explicitly allowed.
        • Migration: If you need to allow browser default behavior for a specific shortcut, set preventDefault: false in its configuration:
          MyPlugin.configure({
            shortcuts: {
              myAction: {
                keys: 'mod+s',
                preventDefault: false, // Example: Allow browser's default save dialog
              },
            },
          });
  • #4327 by @zbeyens

    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

Minor Changes

  • #4327 by @zbeyens
    • New editor DOM state fields available under editor.dom:
      • editor.dom.composing: Boolean, true if the editor is currently composing text (e.g., during IME input).
      • editor.dom.focused: Boolean, true if the editor currently has focus.
      • editor.dom.readOnly: Boolean, true if the editor is in read-only mode. Passing the readOnly prop to PlateContent will sync its value to this state and to the useEditorReadOnly hook.
    • New editor metadata fields:
      • editor.meta.components - stores the plugin components by key
    • New hook useEditorComposing: Allows subscription to the editor's composing state (editor.dom.composing) outside of PlateContent.
    • createPlateEditor and usePlateEditor now accept a readOnly option to initialize the editor in a read-only state. For dynamic read-only changes after initialization, continue to use the readOnly prop on the <Plate> or <PlateContent> component.
    • New plugin field: editOnly (boolean or object).
      • When true or when specific properties are true in the object, Plate will disable certain plugin behaviors (handlers, rendering, injections) in read-only mode and re-enable them if the editor becomes editable.
      • By default, render, handlers, and inject are considered edit-only (true). normalizeInitialValue defaults to always active (false).
      • Example: editOnly: { render: false, normalizeInitialValue: true } would make rendering active always, but normalization only in edit mode.
    • New plugin field: render.as (keyof HTMLElementTagNameMap).
      • Specifies the default HTML tag name to be used by PlateElement (default: 'div') or PlateLeaf (default: 'span') when rendering the node, but only if no custom node.component is provided for the plugin.
      • Example: render: { as: 'h1' } would make the plugin render its node as an <h1> tag by default without the need to provide a custom component.
    • New plugin field: node.isContainer (boolean).
      • When true, indicates that the plugin's elements are primarily containers for other content.
    • New plugin field: node.isStrictSiblings (boolean).
      • When true, indicates that the element enforces strict sibling type constraints and only allows specific siblings (e.g., td can only have td siblings, column can only have column siblings).
      • Used by editor.tf.insertExitBreak functionality to determine appropriate exit points in nested structures.
    • New plugin field: rules (object).
      • Configures common editing behaviors declaratively instead of overriding editor methods. See documentation for more details.
      • rules.break: Controls Enter key behavior (empty, default, emptyLineEnd, splitReset)
      • rules.delete: Controls Backspace key behavior (start, empty)
      • rules.merge: Controls block merging behavior (removeEmpty)
      • rules.normalize: Controls normalization behavior (removeEmpty)
      • rules.selection: Controls cursor positioning behavior (affinity)
      • rules.match: Conditional rule application based on node properties
    • Plugin shortcuts can now automatically leverage existing plugin transforms by specifying the transform name, in addition to custom handlers.
    • New editor transform methods for keyboard handling:
      • editor.tf.escape: Handle Escape key events. Returns true if the event is handled.
      • editor.tf.moveLine: Handle ArrowDown and ArrowUp key events with reverse option for direction. Returns true if the event is handled.
      • editor.tf.selectAll: Handle Ctrl/Cmd+A key events for selecting all content. Returns true if the event is handled.
      • editor.tf.tab: Handle Tab and Shift+Tab key events with reverse option for Shift+Tab. Returns true if the event is handled.

@platejs/[email protected]

  • #4327 by @zbeyens

    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.
  • #4327 by @zbeyens

    • Node type definitions (e.g., TImageElement, TParagraphElement) previously co-located with their respective plugin packages (like @udecode/plate-media) have been centralized into @platejs/utils. These are typically re-exported via the main platejs package.

      • Migration: Update imports for these types to pull from platejs.

        // Before
        // import { TImageElement } from '@udecode/plate-media';
         
        // After
        import { TImageElement } from 'platejs';
    • Removed structuralTypes option from useSelectionFragment and useSelectionFragmentProp. These hooks now automatically use plugin.node.isContainer from enabled plugins.

    • Removed:

      • createNodesHOC
      • createNodesWithHOC
      • createNodeHOC
    • Removed usePlaceholderState hook.

      • Migration: Use the BlockPlaceholderPlugin (typically from platejs) instead of the withPlaceholders HOC and usePlaceholderState. Configure placeholders directly within the BlockPlaceholderPlugin options.
        // Example BlockPlaceholderPlugin configuration
        BlockPlaceholderPlugin.configure({
          options: {
            className:
              'before:absolute before:cursor-text before:opacity-30 before:content-[attr(placeholder)]',
            placeholders: {
              [ParagraphPlugin.key]: 'Type something...',
              // ...other placeholders
            },
            query: ({ editor, path }) => {
              // Example query: only show for top-level empty blocks
              return (
                path.length === 1 && editor.api.isEmpty(editor.children[path[0]])
              );
            },
          },
        });

@platejs/[email protected]

  • #4327 by @zbeyens

    • Copilot API method changes:
      • editor.api.copilot.accept is now editor.tf.copilot.accept.
      • editor.api.copilot.acceptNextWord is now editor.tf.copilot.acceptNextWord.
      • editor.api.copilot.reset is now editor.api.copilot.reject.
    • Removed Default Shortcuts for Copilot:
      • Only accept (Tab) and reject (Escape) shortcuts are included by default for CopilotPlugin.
      • acceptNextWord and triggerSuggestion shortcuts must now be configured manually using the shortcuts field when configuring the plugin.
      • Example:
        CopilotPlugin.configure({
          // ... other options
          shortcuts: {
            acceptNextWord: {
              keys: 'mod+right',
            },
            triggerSuggestion: {
              keys: 'ctrl+space',
            },
          },
        });
  • #4327 by @zbeyens

    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens

    • Package @udecode/plate-alignment has been deprecated.

    • TextAlignPlugin (formerly AlignPlugin) has been moved to the @platejs/basic-styles package.

    • Migration:

      • Remove @udecode/plate-alignment from your dependencies.
      • Add @platejs/basic-styles to your dependencies if not already present.
      • Import TextAlignPlugin from @platejs/basic-styles/react.
    • Renamed AlignPlugin to TextAlignPlugin and changed plugin key from 'align' to 'textAlign'.

      // Before
      import { AlignPlugin } from '@udecode/plate-alignment/react';
       
      // After
      import { TextAlignPlugin } from '@platejs/basic-styles/react';
    • setAlign signature change:

    // Before
    setAlign(editor, { value: 'center', setNodesOptions });
     
    // After
    setAlign(editor, 'center', setNodesOptions);
    • Removed useAlignDropdownMenu and useAlignDropdownMenuState. Use it in your own codebase, for example:
    export function AlignToolbarButton() {
      const editor = useEditorRef();
      const value = useSelectionFragmentProp({
        defaultValue: 'start',
        structuralTypes,
        getProp: (node) => node.align,
      });
     
      const onValueChange = (newValue: string) => {
        editor.tf.textAlign.setNodes(newValue as Alignment);
        editor.tf.focus();
      };
     
      // ...
    }

@platejs/[email protected]

  • #4327 by @zbeyens

    • Replaced BaseAutoformatPlugin with AutoformatPlugin, which is no longer a React plugin. Migration: Replace @udecode/plate-autoformat/react import with @udecode/plate-autoformat.
  • #4327 by @zbeyens

    • The following plugins now default to editOnly: true. This means their core functionalities (handlers, rendering injections, etc.) will be disabled when the editor is in read-only mode. To override this behavior for a specific plugin, configure its editOnly field. For example, SomePlugin.configure({ editOnly: false }).
  • #4327 by @zbeyens

    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Package @udecode/plate-basic-elements has been deprecated.
    • BasicElementsPlugin has been renamed to BasicBlocksPlugin.
    • Its plugins have been moved to the new @platejs/basic-nodes package.
    • Migration:
      • Replace @udecode/plate-basic-elements with @platejs/basic-nodes in your dependencies.
      • Update import paths from @udecode/plate-basic-elements/react to @platejs/basic-nodes/react.
      • For detailed changes to individual plugins, default HTML tags, and shortcut configurations, refer to the changeset for @platejs/basic-nodes.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Package @udecode/plate-basic-marks has been deprecated.
    • Its plugins have been moved to the new @platejs/basic-nodes package.
    • Migration:
      • Replace @udecode/plate-basic-marks with @platejs/basic-nodes in your dependencies.
      • Update import paths from @udecode/plate-basic-marks/react to @platejs/basic-nodes/react.
      • For detailed changes to individual plugins, default HTML tags, and shortcut configurations, refer to the changeset for @platejs/basic-nodes.

@platejs/[email protected]

  • #4327 by @zbeyens
    • The packages @udecode/plate-basic-elements and @udecode/plate-basic-marks have been deprecated. All their plugins are now consolidated into the new @platejs/basic-nodes package.
    • Migration:
      • Replace @udecode/plate-basic-elements and @udecode/plate-basic-marks in your dependencies with @platejs/basic-nodes.
      • Update all import paths from @udecode/plate-basic-elements/react or @udecode/plate-basic-marks/react to @platejs/basic-nodes/react.
      • CodeBlockPlugin is not part of @platejs/basic-nodes. Ensure it is imported from @platejs/code-block/react.
    • SkipMarkPlugin (standalone) is removed. Its functionality is now built into the core editor. To enable boundary clearing for a specific mark, configure the mark plugin directly: plugin.configure({ rules: { selection: { affinity: 'outward' } } }).
    • Default HTML Tag Changes:
      • Blocks: Element plugins in @udecode/plate-basic-nodes (e.g., BlockquotePlugin, HeadingPlugin, HorizontalRulePlugin) now default to rendering with specific HTML tags (<blockquote>, <h1>-<h6>, <hr> respectively). ParagraphPlugin still defaults to <div>. If you relied on previous defaults or need different tags, provide a custom component or use the render.as option.
      • Marks: Mark plugins in @udecode/plate-basic-nodes (e.g., BoldPlugin, CodePlugin, ItalicPlugin) now default to specific HTML tags (<strong>, <code>, <em> respectively). If you relied on previous defaults or need different tags, provide a custom component or use the render.as option.
    • Removed Default Shortcuts:
      • Default keyboard shortcuts are no longer bundled with most plugins (exceptions: bold, italic, underline).
      • Configure shortcuts manually via the shortcuts field in plugin configuration.
      • Example (Block Plugins):
        H1Plugin.configure({ shortcuts: { toggle: { keys: 'mod+alt+1' } } });
        BlockquotePlugin.configure({
          shortcuts: { toggle: { keys: 'mod+shift+period' } },
        });
      • Example (Mark Plugins):
        CodePlugin.configure({ shortcuts: { toggle: { keys: 'mod+e' } } });
        StrikethroughPlugin.configure({
          shortcuts: { toggle: { keys: 'mod+shift+x' } },
        });
        SubscriptPlugin.configure({
          shortcuts: { toggle: { keys: 'mod+comma' } },
        });
        SuperscriptPlugin.configure({
          shortcuts: { toggle: { keys: 'mod+period' } },
        });
        HighlightPlugin.configure({
          shortcuts: { toggle: { keys: 'mod+shift+h' } },
        });

@platejs/[email protected]

  • #4327 by @zbeyens
    • Package @udecode/plate-block-quote has been deprecated.
    • BlockquotePlugin has been moved to the @platejs/basic-nodes package.
    • Migration:
      • Remove @udecode/plate-block-quote from your dependencies.
      • Add @platejs/basic-nodes to your dependencies if not already present.
      • Import BlockquotePlugin from @platejs/basic-nodes/react.

@platejs/[email protected]

  • #4327 by @zbeyens

    • Package @udecode/plate-break has been deprecated.

    • SoftBreakPlugin has been removed. Migration:

      • For shift+enter rules: no migration is needed - this behavior is built into Plate by default.
      • For enter rules: use plugin.configure({ rules: { break: { default: 'lineBreak' } } }) to insert a line break instead of a hard break on Enter keydown when the selection is within the configured node type.
      • For more complex break rules: use overrideEditor to override the insertBreak transform with custom logic.
    • ExitBreakPlugin has been moved to @platejs/utils (which is re-exported via platejs) with a simplified API and improved behavior.

      • Behavior Change: Instead of always exiting to the root level of the document, exiting will now insert a block to the nearest exitable ancestor that has isStrictSiblings: false. This means deeply nested structures (like tables in columns) are exitable at many levels.

      • Migration:

        • Remove @udecode/plate-break from your dependencies.

        • Replace @udecode/plate-break import with platejs.

        • Important: If not using Plate plugins, you must set isStrictSiblings: true on your custom node plugins that can't have paragraph siblings for exit break to work correctly.

        • Replace complex rule-based configuration with simple shortcuts:

          // Before (old API)
          ExitBreakPlugin.configure({
            options: {
              rules: [
                { hotkey: 'mod+enter' },
                { hotkey: 'mod+shift+enter', before: true },
              ],
            },
          });
           
          // After (new API)
          ExitBreakPlugin.configure({
            shortcuts: {
              insert: { keys: 'mod+enter' },
              insertBefore: { keys: 'mod+shift+enter' },
            },
          });

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens

    • CaptionPlugin option options.plugins (accepting an array of PlatePlugin) has been renamed to options.query.allow (accepting an array of plugin keys).

    • Migration:

      // Before
      CaptionPlugin.configure({
        options: {
          plugins: [ImagePlugin], // ImagePlugin is an example
        },
      });
       
      // After
      CaptionPlugin.configure({
        options: {
          query: {
            allow: [ImagePlugin.key], // Use the plugin's key
          },
        },
      });
  • #4327 by @zbeyens

    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens
    • CodeBlockPlugin now defaults to rendering the code block container with a <pre> HTML tag if no custom component is provided for CodeBlockElement (or the plugin key code_block).

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens

    • CommentsPlugin has been renamed to CommentPlugin.
    • Update imports and plugin configurations accordingly.
      • Example: CommentsPlugin.key becomes CommentPlugin.key.
    • Package name has been changed to @platejs/comment.
  • #4327 by @zbeyens

    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens

    • The following plugins now default to editOnly: true. This means their core functionalities (handlers, rendering injections, etc.) will be disabled when the editor is in read-only mode. To override this behavior for a specific plugin, configure its editOnly field. For example, SomePlugin.configure({ editOnly: false }).
  • #4327 by @zbeyens

    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens

    • The following plugins now default to editOnly: true. This means their core functionalities (handlers, rendering injections, etc.) will be disabled when the editor is in read-only mode. To override this behavior for a specific plugin, configure its editOnly field. For example, SomePlugin.configure({ editOnly: false }).
  • #4327 by @zbeyens

    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens

    • The following plugins now default to editOnly: true. This means their core functionalities (handlers, rendering injections, etc.) will be disabled when the editor is in read-only mode. To override this behavior for a specific plugin, configure its editOnly field. For example, SomePlugin.configure({ editOnly: false }).
  • #4327 by @zbeyens

    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens

    • Removed setBlockBackgroundColor
    • Removed setFontSize – use tf.fontSize.addMark instead:
    // Before
    editor.api.fontSize.addMark('16px');
     
    // After
    editor.tf.fontSize.addMark('16px');
    • Removed useColorInput. Use it in your own codebase, for example:
    function ColorInput() {
      const inputRef = React.useRef<HTMLInputElement | null>(null);
     
      const onClick = () => {
        inputRef.current?.click();
      };
     
      // ...
    }
    • Removed useColorsCustom and useColorsCustomState. Use it in your own codebase, for example:
    function ColorCustom({ color, colors, customColors, updateCustomColor }) {
      const [customColor, setCustomColor] = React.useState<string>();
      const [value, setValue] = React.useState<string>(color || '#000000');
     
      React.useEffect(() => {
        if (
          !color ||
          customColors.some((c) => c.value === color) ||
          colors.some((c) => c.value === color)
        ) {
          return;
        }
     
        setCustomColor(color);
      }, [color, colors, customColors]);
     
      const computedColors = React.useMemo(
        () =>
          customColor
            ? [
                ...customColors,
                {
                  isBrightColor: false,
                  name: '',
                  value: customColor,
                },
              ]
            : customColors,
        [customColor, customColors]
      );
     
      const updateCustomColorDebounced = React.useCallback(
        debounce(updateCustomColor, 100),
        [updateCustomColor]
      );
     
      const inputProps = {
        value,
        onChange: (e: React.ChangeEvent<HTMLInputElement>) => {
          setValue(e.target.value);
          updateCustomColorDebounced(e.target.value);
        },
      };
     
      // ...
    }
    • Removed useColorDropdownMenu and useColorDropdownMenuState. Use it in your own codebase, for example:
    export function FontColorToolbarButton({ nodeType }) {
      const editor = useEditorRef();
     
      const selectionDefined = useEditorSelector(
        (editor) => !!editor.selection,
        []
      );
     
      const color = useEditorSelector(
        (editor) => editor.api.mark(nodeType) as string,
        [nodeType]
      );
     
      const [selectedColor, setSelectedColor] = React.useState<string>();
      const [open, setOpen] = React.useState(false);
     
      const onToggle = React.useCallback(
        (value = !open) => {
          setOpen(value);
        },
        [open, setOpen]
      );
     
      const updateColor = React.useCallback(
        (value: string) => {
          if (editor.selection) {
            setSelectedColor(value);
            editor.tf.select(editor.selection);
            editor.tf.focus();
            editor.tf.addMarks({ [nodeType]: value });
          }
        },
        [editor, nodeType]
      );
     
      const clearColor = React.useCallback(() => {
        if (editor.selection) {
          editor.tf.select(editor.selection);
          editor.tf.focus();
          if (selectedColor) {
            editor.tf.removeMarks(nodeType);
          }
          onToggle();
        }
      }, [editor, selectedColor, onToggle, nodeType]);
     
      React.useEffect(() => {
        if (selectionDefined) {
          setSelectedColor(color);
        }
      }, [color, selectionDefined]);
     
      // ...
    }

@platejs/[email protected]

  • #4327 by @zbeyens
    • Package @udecode/plate-heading has been deprecated.
      • HeadingPlugin and individual heading plugins (e.g., H1Plugin) have been moved to @platejs/basic-nodes.
        • Migration: Import from @platejs/basic-nodes/react (e.g., import { HeadingPlugin } from '@platejs/basic-nodes/react';).
      • TocPlugin has been moved to @platejs/toc.
        • Migration: Add @platejs/toc to your dependencies and import TocPlugin from @platejs/toc/react.
    • Remove @udecode/plate-heading from your dependencies.
    • HEADING_LEVELS has been removed. Use KEYS.heading instead.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Package @udecode/plate-highlight has been deprecated.
    • HighlightPlugin has been moved to the @platejs/basic-nodes package.
    • Migration:
      • Remove @udecode/plate-highlight from your dependencies.
      • Add @platejs/basic-nodes to your dependencies if not already present.
      • Import HighlightPlugin from @platejs/basic-nodes/react.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Package @udecode/plate-horizontal-rule has been deprecated.
    • HorizontalRulePlugin has been moved to the @platejs/basic-nodes package.
    • Migration:
      • Remove @udecode/plate-horizontal-rule from your dependencies.
      • Add @platejs/basic-nodes to your dependencies if not already present.
      • Import HorizontalRulePlugin from @platejs/basic-nodes/react.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Package @udecode/plate-indent-list has been renamed to @platejs/list.
    • Migration:
      • Rename all import paths from @udecode/plate-indent-list to @platejs/list.
      • Update your package.json: remove @udecode/plate-indent-list and add @platejs/list.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Package @udecode/plate-kbd has been deprecated.
    • KbdPlugin has been moved to the @platejs/basic-nodes package.
    • Migration:
      • Remove @udecode/plate-kbd from your dependencies.
      • Add @platejs/basic-nodes to your dependencies if not already present.
      • Import KbdPlugin from @platejs/basic-nodes/react.

@platejs/[email protected]

  • #4327 by @zbeyens

    • Delete backward from a column start will merge into the previous column
  • #4327 by @zbeyens

    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens

    • Package @udecode/plate-line-height has been deprecated.

    • LineHeightPlugin has been moved to the @platejs/basic-styles package.

    • Migration:

      • Remove @udecode/plate-line-height from your dependencies.
      • Add @platejs/basic-styles to your dependencies if not already present.
      • Import LineHeightPlugin from @platejs/basic-styles/react.
    • setLineHeight signature change:

    // Before
    setLineHeight(editor, { value: 1.5, setNodesOptions });
     
    // After
    setLineHeight(editor, 1.5, setNodesOptions);
    • Removed useLineHeightDropdownMenu and useLineHeightDropdownMenuState. Use it in your own codebase, for example:
    export function LineHeightToolbarButton() {
      const editor = useEditorRef();
      const { defaultNodeValue, validNodeValues: values = [] } =
        editor.getInjectProps(LineHeightPlugin);
     
      const value = useSelectionFragmentProp({
        defaultValue: defaultNodeValue,
        getProp: (node) => node.lineHeight,
      });
     
      const onValueChange = (newValue: string) => {
        editor.tf.lineHeight.setNodes(Number(newValue));
        editor.tf.focus();
      };
     
      // ...
    }

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens

    • The previous @udecode/plate-list (classic list implementation) has been moved to @platejs/list-classic.
      • Migration for users of the classic list:
        • Rename all import paths from @udecode/plate-list to @platejs/list-classic.
        • Update your package.json: remove the old @udecode/plate-list (if it was a direct dependency) and add @platejs/list-classic.
    • This package, @platejs/list, now contains the functionality previously in @udecode/plate-indent-list (indent-based list system).
      • Plugin names have been generalized: IndentListPlugin is now ListPlugin, BaseIndentListPlugin is BaseListPlugin, etc. (*IndentList* -> *List*).
      • The primary plugin key is now list (e.g., ListPlugin.key) instead of listStyleType.
      • Constants for list keys previously in INDENT_LIST_KEYS are now available under KEYS from platejs.
        • Migration for constants:
          • INDENT_LIST_KEYS.listStyleType -> KEYS.listType
          • INDENT_LIST_KEYS.todo -> KEYS.listTodo
          • INDENT_LIST_KEYS.checked -> KEYS.listChecked
          • Other INDENT_LIST_KEYS.* map to KEYS.* accordingly.
      • Removed listStyleTypes option from ListPlugin. You should control list rendering via render.belowNodes instead.
      • Removed renderListBelowNodes.
    • For changelogs of the indent-based list system (now in this package) version <=48 (when it was @udecode/plate-indent-list), refer to its archived changelog.
  • #4327 by @zbeyens

    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Removed Default Shortcuts for BulletedListPlugin and NumberedListPlugin.
      • These shortcuts must now be configured manually using the shortcuts field.
      • Example:
        BulletedListPlugin.configure({
          shortcuts: { toggle: { keys: 'mod+alt+5' } },
        });
        NumberedListPlugin.configure({
          shortcuts: { toggle: { keys: 'mod+alt+6' } },
        });
    • Package @udecode/plate-list has been moved to @platejs/list-classic.
      • Migration:
        • Rename all import paths from @udecode/plate-list to @platejs/list-classic.
        • Update your package.json: remove @udecode/plate-list and add @platejs/list-classic.
    • For changelogs of @udecode/plate-list version <=48, refer to its archived changelog.

@platejs/[email protected]

  • #4327 by @zbeyens

    • Function indentListToMdastTree has been renamed to listToMdastTree to align with the list plugin renames (IndentListPlugin -> ListPlugin).
  • #4327 by @zbeyens

    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens

    • The type TMentionInputElement has been removed.
    • Use TComboboxInputElement from @udecode/plate instead for input elements, as mention functionality is built upon the combobox.
  • #4327 by @zbeyens

    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens

    • Package @udecode/plate-node-id has been deprecated.

    • NodeIdPlugin functionality is now part of @platejs/core and is enabled by default.

    • Migration:

      • Remove NodeIdPlugin from your explicit plugin list if it was added manually.

      • Remove @udecode/plate-node-id from your dependencies.

      • If you had NodeIdPlugin configured with options, move these options to the nodeId field in your main editor configuration (createPlateEditor or usePlateEditor options). Example:

        // Before
        // const editor = usePlateEditor({
        //   plugins: [
        //     NodeIdPlugin.configure({ /* ...your options... */ }),
        //   ],
        // });
         
        // After
        const editor = usePlateEditor({
          nodeId: {
            /* ...your options... */
          },
          // ...other editor options
        });
      • If you want to disable automatic node ID generation (to replicate behavior if you weren't using NodeIdPlugin before), set nodeId: false in your editor configuration.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Package @udecode/plate-normalizers has been deprecated.
    • Its plugins have been moved to platejs (which is re-exported via platejs).
    • Migration:
      • Remove @udecode/plate-normalizers from your dependencies.
      • Update import paths to use platejs

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens – Package @udecode/plate-reset-node has been deprecated. Its functionality (e.g., ResetNodePlugin) is now exclusively configured using the rules.break and rules.delete options on plugin definitions. Migration:

    • Remove @udecode/plate-reset-node from your dependencies.
    • Remove any usage of ResetNodePlugin from your project.
    • Configure reset behaviors directly on the relevant plugins by defining rules.break and/or rules.delete.

    Example: Resetting a Blockquote to a Paragraph

    ResetNodePlugin.configure({
      options: {
        rules: [
          {
            types: [BlockquotePlugin.key],
            defaultType: ParagraphPlugin.key,
            hotkey: 'Enter',
            predicate: (editor) =>
              editor.api.isEmpty(editor.selection, { block: true }),
          },
        ],
      },
    });
     
    // After
    BlockquotePlugin.configure({
      rules: {
        break: { empty: 'reset' },
        delete: { start: 'reset' },
      },
    });

    For custom reset logic (previously onReset):

    // Before
    ResetNodePlugin.configure({
      options: {
        rules: [
          {
            types: [CodeBlockPlugin.key],
            defaultType: ParagraphPlugin.key,
            hotkey: 'Enter',
            predicate: isCodeBlockEmpty,
            onReset: unwrapCodeBlock,
          },
        ],
      },
    });
     
    // After
    CodeBlockPlugin.configure({
      rules: {
        delete: { empty: 'reset' },
      },
    }).overrideEditor(({ editor, tf: { resetBlock } }) => ({
      transforms: {
        resetBlock(options) {
          if (
            editor.api.block({
              at: options?.at,
              match: { type: editor.getType(CodeBlockPlugin.key) },
            })
          ) {
            unwrapCodeBlock(editor);
            return;
          }
     
          return resetBlock(options);
        },
      },
    }));

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens

    • The following plugins now default to editOnly: true. This means their core functionalities (handlers, rendering injections, etc.) will be disabled when the editor is in read-only mode. To override this behavior for a specific plugin, configure its editOnly field. For example, SomePlugin.configure({ editOnly: false }).
  • #4327 by @zbeyens

    • Package @udecode/plate-select has been deprecated.
    • SelectOnBackspacePlugin has been removed. This behavior is now built into Plate by default: delete (backward/forward) at the start of a block will select the previous/next void block instead of removing it.
    • DeletePlugin has been removed. This behavior is now built into Plate by default: delete (backward/forward) from an empty block will remove it instead of merging.
    • RemoveEmptyNodesPlugin has been removed. This behavior is now available through the rules: { normalize: { removeEmpty: true } } configuration on individual plugins.
    • Migration:
      • Remove @udecode/plate-select from your dependencies.
      • Remove any usage of SelectOnBackspacePlugin, DeletePlugin from your project.
      • Replace RemoveEmptyNodesPlugin.configure({ options: { types: ['custom'] } }) with CustomPlugin.configure({ rules: { normalize: { removeEmpty: true } } }). This is used by our LinkPlugin.

@platejs/[email protected]

  • #4327 by @zbeyens

    • The following plugins now default to editOnly: true. This means their core functionalities (handlers, rendering injections, etc.) will be disabled when the editor is in read-only mode. To override this behavior for a specific plugin, configure its editOnly field. For example, SomePlugin.configure({ editOnly: false }).
  • #4327 by @zbeyens

    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens

    • The following plugins now default to editOnly: true. This means their core functionalities (handlers, rendering injections, etc.) will be disabled when the editor is in read-only mode. To override this behavior for a specific plugin, configure its editOnly field. For example, SomePlugin.configure({ editOnly: false }).
  • #4327 by @zbeyens

    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.
  • #4327 by @zbeyens

    • The type TSlashInputElement has been removed.
    • Use TComboboxInputElement from platejs instead for Slash Command input elements, as slash command functionality is built upon the combobox.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.

@platejs/[email protected]

  • #4327 by @zbeyens

    • The following plugins now default to editOnly: true. This means their core functionalities (handlers, rendering injections, etc.) will be disabled when the editor is in read-only mode. To override this behavior for a specific plugin, configure its editOnly field. For example, SomePlugin.configure({ editOnly: false }).
  • #4327 by @zbeyens

    • Package @udecode/plate-trailing-block has been deprecated.
    • Its functionality (e.g., TrailingBlockPlugin) has been moved to @platejs/utils (which is re-exported via platejs).
    • Migration:
      • Remove @udecode/plate-trailing-block from your dependencies.
      • Update import paths to use platejs (e.g., import { TrailingBlockPlugin } from 'platejs';).

@platejs/[email protected]

  • #4327 by @zbeyens
    • Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code.