Skip to content

Undo / Redo are not working when collaboration is enabled #2244

@notABot101010

Description

@notABot101010

Describe the bug

Hello and thank you for the work on BlockNote!

It seems that undo / redo (Ctrl + Z / Ctrl + Y) are not working when the collaboration feature with Yjs is enabled.

When enabling collaboration with a minimal YJsProvider, Ctrl + Z does nothing. If we comment the collaboration part of the config it's working again.

Also, when trying to implement it by hand with the following code, it's still not working:

const undoHandler = useCallback((e: KeyboardEvent) => {
    if ((e.metaKey || e.ctrlKey) && (e.key === 'z' || e.key === 'Z')) {
      console.log('undo'); // displayed
      editor.undo(); // <- NOT WORKING
    }
  }, []);

  useWindowEvent('keydown', undoHandler);

To Reproduce
Here is a minimal reproduction in a sandbox: https://stackblitz.com/edit/github-qp3au5av?file=src%2FApp.tsx

And the code, in case the sandbox is not working:

App.jsx

import '@blocknote/core/fonts/inter.css';
import { BlockNoteView } from '@blocknote/mantine';
import '@blocknote/mantine/style.css';
import { useCreateBlockNote } from '@blocknote/react';
import * as Y from 'yjs';

export default function App() {
  const ydoc = new Y.Doc();
  const yLoggingProvider = new YProvider(ydoc);
  const editor = useCreateBlockNote({
    collaboration: {
      provider: yLoggingProvider,
      fragment: ydoc.getXmlFragment('blocks'),
      user: {
        name: 'My Username',
        color: '#ff0000',
      },
      // showCursorLabels: 'always',
    },
  });

  // Renders the editor instance using a React component.
  return <BlockNoteView editor={editor} />;
}

export class YProvider {
  private doc: Y.Doc;
  private name: string;

  constructor(doc: Y.Doc, name = 'YProvider') {
    this.doc = doc;
    this.name = name;

    this.doc.on('update', this.onLocalUpdate);

    console.log(`[${this.name}] provider started`);
  }

  private onLocalUpdate = (update: Uint8Array, origin: any) => {
    Y.applyUpdate(this.doc, update);
  };

  /**
   * Apply a received update from an external source.
   * This bypasses the debounce and applies immediately.
   */
  public receiveUpdate(update: Uint8Array): void {
    Y.applyUpdate(this.doc, update, `${this.name}-external`);
  }

  public destroy(): void {
    this.doc.off('update', this.onLocalUpdate);
  }
}

Alternatively, you can try with the official WebrtcProvider as shown in the doc here: https://www.blocknotejs.org/docs/features/collaboration

const provider = new WebrtcProvider("my-document-id", ydoc);
  const editor = useCreateBlockNote({
    collaboration: {
      provider: provider,
      // Where to store BlockNote data in the Y.Doc:
      fragment: ydoc.getXmlFragment("blocks"),
      // Information (name and color) for this user:
      user: {
        name: "My Username",
        color: "#ff0000",
      },
    // showCursorLabels: 'always',
    }
  });

It's not working.

Misc

  • Node version: 25.2
  • Package manager: npm
  • Browser: It's not working with multiple browsers
  • I'm a sponsor and would appreciate if you could look into this sooner than later 💖

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions