Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Backspace doesn't work in shadow root on Firefox #6105

Open
1 task done
vialoh opened this issue Feb 14, 2025 · 3 comments
Open
1 task done

[Bug]: Backspace doesn't work in shadow root on Firefox #6105

vialoh opened this issue Feb 14, 2025 · 3 comments
Labels
Category: Open Source The issue or pull reuqest is related to the open source packages of Tiptap. Type: Bug The issue or pullrequest is related to a bug

Comments

@vialoh
Copy link

vialoh commented Feb 14, 2025

Affected Packages

core, pm, react, extension-*

Version(s)

2.11.5

Bug Description

On Firefox, backspace (and delete) does not remove individual characters. Deleting selections works and deleting lines works, but not individual characters. Works fine in Chrome.

Note that this is in the context of a browser extension, where Firefox sometimes works in strange ways, probably due to restrictions/sandboxing. I was unable to repro the issue in the CodeSandbox, despite it being almost exactly like the actual code we're using. The reason for this is likely because it's not running in the context of a browser extension (content script). If you want to see the bug in production, install our extension and open a job application and then click "Generate Letter" in the "Cover Letter" section of the popup on the right.

Also note that it may not actually be due to the shadow root. It may only be because it's running within a browser extension, but we need to use a shadow root to isolate the elements/styles from the rest of the page.

Browser Used

Firefox

Code Example URL

https://codesandbox.io/p/sandbox/ecstatic-thunder-9qmrgv

Expected Behavior

It should remove characters when pressing backspace/delete.

Additional Context (Optional)

No response

Dependency Updates

  • Yes, I've updated all my dependencies.
@vialoh vialoh added Category: Open Source The issue or pull reuqest is related to the open source packages of Tiptap. Type: Bug The issue or pullrequest is related to a bug labels Feb 14, 2025
@github-project-automation github-project-automation bot moved this to Needs Triage in Tiptap: Issues Feb 14, 2025
@ValeryNo
Copy link

ValeryNo commented Feb 24, 2025

Same here. This does seem to be a bug. Please share if anyone finds workaround.

Exactly same code works in Chrome. This seems to be specific to the shadowRoot

@ValeryNo
Copy link

This can be used as a workaround for now:

        <EditorContent
          editor={editor}
          onKeyDown={(e) => {
            // A workaround for backspace not working under Firefox + shadow root
            if (isFirefoxEnvironment() && getShadowRoot() && e.key === 'Backspace' && editor?.state.selection.empty) {
              const pos = editor?.state.selection.$head.pos;
              if (pos > 0) {
                editor?.commands.deleteRange({ from: pos - 1, to: pos });
              }
            }
...

You can create isFirefoxEnvironment && getShadowRoot with ChatGPT.

@vialoh
Copy link
Author

vialoh commented Feb 27, 2025

@ValeryNo Thank you for sharing your code! Very helpful. I modified it a bit to also handle the delete key and to prevent the backspace from removing the last character of the previous line when backspacing at the start of a line.

import { isFirefox } from './isFirefox';
import type { EditorView } from '@tiptap/pm/view';

/**
 * A workaround to fix TipTap's backspace/delete keys not working correctly in Firefox.
 */
export const handleTipTapKeyDown = (view: EditorView, event: KeyboardEvent): void => {
  if (!isFirefox) {
    return;
  }

  const isBackspace = event.key === 'Backspace';
  const isDelete = event.key === 'Delete';

  if (isBackspace || isDelete) {
    const { state } = view;
    const { selection } = state;
    const { empty, $anchor } = selection;

    if (!empty) {
      return;
    }

    const isAtStartOfLine = $anchor.pos === $anchor.start();

    if ((isBackspace && !isAtStartOfLine) || isDelete) {
      const from = isBackspace ? $anchor.pos - 1 : $anchor.pos;
      const tr = state.tr.deleteRange(from, from + 1);

      view.dispatch(tr);
      event.preventDefault();
    }
  }
};

I didn't include a check for the shadow root since my TipTap editor always runs in a shadow root, so in your case you may need to add a shadow root check.

Also, instead of passing this as the EditorContent's onKeyDown property, this should be passed as the useEditor hook's editorProps:

  const editor = useEditor({
    editorProps: {
      handleKeyDown: handleTipTapKeyDown,
    },
  });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Category: Open Source The issue or pull reuqest is related to the open source packages of Tiptap. Type: Bug The issue or pullrequest is related to a bug
Projects
Status: Needs Triage
Development

No branches or pull requests

2 participants