8

hi I'm trying to create a react contenteditable div component that works like an input field but with some additional features that I want to implement, but since there are just few features, I want to implement it myself and not use something like slatejs or draftjs that do so much heavy lifting.

my idea is that I should have a controlled contenteditable div that I listen on events that insert some text. (like general idea of react controlled components)

it looked straightforward. I should listen on keydown events and on each event I just insert the corresponding character(event.key) into my state. however I found that on mobile devices with touch keyboards this value(event.key) is always 'Unidentified'.

also sometimes the input events have a 'data' property that determines the inserted value. but in touch keyboard that event doesn't have 'data' property.

so my question is how can we get inserted characters in a way that works globally on desktop and mobile? how do draftjs and slatejs authors detect inserted characters (even on touch mobile) and update their state?

vsync
  • 118,978
  • 58
  • 307
  • 400
Amin_mmz
  • 394
  • 4
  • 14

1 Answers1

8

I finally got the answer it turns out that in react there is an event called onBeforeInput that can be used on contenteditable divs and has a property called data that corresponds to the text that is going to be inserted (on both mobile and desktop). this event is cancelable so you can call preventDefault on it and update your state. unfortunately this event was not mentioned in any of react docs (!!) and I found it from an issue on their github repo.

Amin_mmz
  • 394
  • 4
  • 14
  • 1
    I believe `beforeinput` is a vanilla JavaScript event, but it isn't very well-documented, either. On MDN, the event's page, https://developer.mozilla.org/en-US/docs/Web/Events/beforeinput, is linked to from, e.g., the InputEvent page, but is red, meaning it doesn't exist yet. On another note, React's version seems more full-featured, for example it has the `data` property even on browsers that don't support it natively yet, like Firefox. – trysis Jun 23 '18 at 18:57
  • Not sure if wrong or this information is outdated but if I `console.log` beforeinput event, it says `canceable: false`. – Solo Mar 08 '19 at 18:10
  • Looks like almost 60% of users don't have support for `beforeinput` in their browser https://caniuse.com/?search=beforeinput – ArneHugo May 03 '21 at 19:56
  • 1
    @ArneHugo No, actually it's not like that. It seems that React under the hood converts the `beforeinput` event into something specific to each browser that has good support. for chrome it is `textInput` (notice the uppercase i). – Amin_mmz May 06 '21 at 20:03
  • Nice. By using `onBeforeInput`, is it possible to change the value of the `contentEditable` without breaking undo (`ctrl+Z`)? – ArneHugo May 06 '21 at 20:28
  • @ArneHugo I think if you want to use it as a controlled component, you need to take control of everything and handle the `undo` yourself. But it's surely worth a try! – Amin_mmz May 15 '21 at 10:34
  • 2
    How do you know where the **caret** was at when a key was pressed (known through `data` property of the event), so a character could be added to the state? – vsync Oct 23 '22 at 14:04