As I was reinventing the wheel for fun and profit, I isolated an interesting behavior that appears to only occur in Android Chrome.
I am formatting a text input as the user types, which means setting the input value, losing the caret position. No problem - just track the caret position, and set it back after you change the value (adjusting for added/removed characters) in the input event callback.
Works great! Except for Android Chrome (Android 7, Chrome 58.0.3029.83) - I set the caret position, observe the caret position where I expect - then on keyup event it is magically moved - after input event but before keyup event.
Tracking caret positions
You can see this for yourself in this (exceedingly simplified) fiddle. I even output the relevant data on screen so you don't have to hook up a debugger to see it.
Type "abcd" and get:
Numbers are caret positions from this.selectionStart
D = keyDown, I = Input, C = position Changed to, U = keyUp
D: 0 | I: 0 | C: 1 | U: 1
D: 1 | I: 1 | C: 2 | U: 2
D: 2 | I: 2 | C: 3 | U: 3
D: 3 | I: 3 | C: 5 | U: 4 //<- This 4 is the culprit
Where every other browser tested (IE11, iOS Safari, Desktop Chrome) gives you:
D: 0 | I: 1 | C: 1 | U: 1
D: 1 | I: 2 | C: 2 | U: 2
D: 2 | I: 3 | C: 3 | U: 3
D: 3 | I: 4 | C: 5 | U: 5
Is there an event in there I'm missing? It's not in the docs that I can find, though I know virtual keyboards get a little janky. I'd love to find out exactly where this is happening so I can nuke it.
Also tried
beforeinput
, compositionstart
, and compositionend
events. The only one that is triggered is compositionstart
, between the keydown
and input
events. It shows the caret position I would expect to see at that time.
Typing "abcd" then hitting backspace in Android Chrome gives you:
D: 4 | I: 3 | C: 5 | U: 5
Seeming to indicate that whatever is moving the caret did not do so in this case.
Not looking for a workaround. The workaround is to set the caret again in the keyup event. I'm asking to see if anyone knows a less-wrong answer.