Firefox shadow DOM contenteditable bug

This was almost a bug report and not a forum post, but as I investigated this further, this turned out to be a Firefox bug that unfortunately happens to affect my use of CM6.

I have found that if you load CodeMirror in Firefox and inside a shadow DOM, then the cursor will be missing once the editor regains focus after having lost it previously, and moving the cursor e.g. with arrow keys will be impossible.

I created a minimal fiddle that reproduces the problem: Edit fiddle - JSFiddle - Code Playground
You can open it in Chromium-based browsers and it will work fine, unlike in Firefox. The problem goes away if a shadow DOM is not involved.

Loading the drawSelection extension will make the cursor appear once the editor regains focus (probably because this extension makes it so that drawing cursors becomes the responsibility of the editor and not the browser’s contentEditable mechanism), but you still won’t be able to move the cursor with the keyboard: Edit fiddle - JSFiddle - Code Playground

I thought there could be a small possibility that this could actually be a Firefox bug, so I set up this even more simple fiddle: Edit fiddle - JSFiddle - Code Playground
…and as it turns out, this is a Firefox bug (reproduced in Firefox 98).

It appears that contenteditables inside shadow DOMs have been problematic for Firefox for years now. I found multiple bug reports related to this combination and also some StackOverflow discussions (e.g.) but none of them seem to quite match the current incorrect behavior.

This is clearly a Firefox problem and not a problem with CodeMirror; I’m posting this here more so that others don’t waste hours chasing this, but if anyone has a workaround that can be applied to CM6, make sure to let us know :slight_smile:

EDIT: I finally found the bug report for this specific problem: 1496769 - a contenteditable element inside an element with tabindex(which is inside a Shadow DOM), fails to display the caret when the focus is changed inbetween shadow elements

Ugh, that’s annoying. Did you investigate why keyboard motion breaks? I’d expect, since CodeMirror handles that in key bindings, that as long as focus is in the right element that continues to work.

The editor’s hasFocus state always updates correctly as you tab away and back into it, and it adds and removes the cm-focused class accordingly.

I tried binding a CM command to the ArrowRight key, and it always triggered correctly even when the editor is in the broken state. So the editor is always receiving keyboard events when it should.

My current hypothesis is that, both in the barebones example I’m testing with and in my application, I am not adding in one or more sets of key bindings that would be needed to actually have CM fully control the cursor. In a barebones example, if I add basicSetup to the extensions, the bug is fully gone. See here: Edit fiddle - JSFiddle - Code Playground
I’m not using basicSetup in my application because I don’t actually want most of the code editor features, so I brought in strictly what I thought I needed. I’ll try to hunt down exactly what keymap(s) I need for cursor control and that should be a sufficient workaround.

Adding drawSelection and the defaultKeymap to the extensions is seemingly all that was needed to work around the bug. Now I just need to add some styling to the cursor and the selection highlight to make it more fitting with my application and I think this CM6 integration will be a success story :slight_smile: Thanks for your work and help.

The workaround makes things perfect in desktop Firefox, but on Firefox for Android, at least with Gboard as the keyboard, the behavior will still be very strange. Input will often break completely, repeating the first autocomplete suggestion endlessly as soon as any key is pressed and backspace stops working (instead it also repeats the autocomplete suggestion), and sometimes it feels like there’s some string corruption going on as well (text coming from other parts of the page outside of the editor). It can be usually be brought back to sanity by doing the same thing that also fixed the cursor blinking+movement on desktop Firefox: focusing, by mouse/touch, on some other part of the page, then back on the editor.

At this point I’m not sure I should waste any more time on this, the problem is clearly with the browser. I think I’ll just keep my old textarea-based editor so it is used on Firefox for Android clients.