Focusing inputs within widgets

I have a question regarding focus behavior. I have a few widgets I’m rendering that allow for a somewhat more user-friendly modification of certain Markdown elements (pre-rendering images or tables, for example). The idea is: There is an underlying Markdown representation of the elements which I detect in the SyntaxTree, and then I render block or inline widgets instead of those elements. The user can then modify the elements and, on certain events (button pressing) the widgets are applying the new, modified syntax to the document in a transaction that then also retriggers all the required events for re-rendering the widgets etc.

However, I have noticed that it’s very difficult to “steal” the focus from the editor DOM and apply it to my own widget. Basically, if a user clicks on an element, that element has focus for a fraction of a second and then the editor element itself regains focus.

Since there is this concept of panels and they can have focus, I wonder what I need to do to keep the focus in my widgets. (I do not want to use panels as I would like to completely hide the syntax; panels would need to be positioned above or below the syntax in question, if I understood it correctly).

Telling the editor to ignore events in the widget class doesn’t work, unfortunately. What is the recommended way (if any) to achieve that?

Thanks in advance for any help!

Are you using the ignoreEvent method on the widget to tell the editor to not handle those mouse events?

Yes. After I wrote the topic, I also realized that the view plugins I‘m using for the widgets also support some handlers (although these are too generic if you‘d like to handle multiple elements), so I‘m not sure if I was simply using the wrong approach…?

In any case, here‘s some context if you would like to check the code: here‘s one of these plugins where you can see how I tap into events, and here is the wrapper (since I create many very similar plugins I figured this approach makes sense).

At this point I’m not sure what the problem is and the linked code is more complicated than what I’m willing to dig into, but if you think the library is doing something dodgy, I’d be happy to debug a reduced example.

1 Like

Understandable. I’ll double check if the library is indeed doing something dodgy, and if it is, I’ll write a minimal repro and get back to you. Thanks for your help thus far!

EDIT: If I move the contenteditable field into a child element, it works as expected. After some more digging I found the error, which was 100% on my side and my fault. Sorry to bother you so much again!

Hej Marijn,

I have now dug deeper, removed any code not required to reproduce the behavior and I found out something interesting: Input elements work flawlessly, but contenteditable elements do not work. Somehow, the editor sets any contenteditable field to false upon rendering.

Here is a minimal example:

  • Lines 8:29 → The demo widget that creates a contenteditable DIV alongside a regular input element (in the toDOM method)
  • Lines 29:47 → Ignore that, that just searches for syntax nodes to render
  • Lines 50:61 → That’s a rudimentary ViewPlugin to provide the decorations
  • Lines 63:75 → Creation of a minimal state & view

It’s just the source code as the built example is too large to upload. I hope that is fine? If you do not wish to build it yourself, I can upload the built version somewhere for you to double-check. Basically if you build the index.ts and load it in the example HTML file, you can check that it is not possible to edit the DIV element. However, after programmatically setting the contenteditable field to true in the DevTools, you are able to edit the DIV’s contents without any issue for the editor itself. The input element itself works flawlessly. Also notable: One has to click twice on the contenteditable div. After the first click, the editor itself grabs focus and becomes editable, and only after the second click can you actually edit the contenteditable field.

Widgets intentionally always get set to contenteditable=false, or they would become part of CodeMirror’s editable content element. You should be able to introduce new contenteditable=true child elements inside of them.

1 Like