TypeCellOS / TypeCellOS/BlockNote

Undo / Redo are not working when collaboration is enabled

Open
#2,244 18 comments 0 reactions 1 assignee View on GitHub

@nperez0111 is already working on this.

Since Jan 13, 2026.

bug:P3
Dominant language
TypeScript
Stars
10.2k
Forks
772
Avg merge
3d 11h
Merged PRs (30d)
17

Description

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 💖

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.