javascriptinputrangeselectionkeydown

Wrong input's selectionStart value after pressing arrow key


Here is the scenario to reproduce the problem:

  1. Given input element has test string as a content. Focus given input element by clicking at the end of the input element
  2. After focusing, caret is set at the end of input field (after last symbol t)
  3. At this point - input's element selectionStart property is equal to 4. Which is right
  4. Then press arrow left key on keyboard. After pressing the key, expected input's selectionStart value is 3. But actually selectionStart value equals to 4 again. Which is wrong.

In result, when input's element caret at the end, selectionStart equals 4, but, after pressing left arrow key, caret is set to position 3, but selectionStart equals 4.

In result there is a strange thing, if caret at the end (after symbol t - selectionStart is 4, and if caret one position less (after symbol s) caret is again has selectionStart equal to 4

The question is how to get right selectionStart value? Is it a bug? Why does it happen?

const element = document.getElementById('test');
element.addEventListener('keydown', (event) => {
    console.log(`Keydown. Selection start: ${element.selectionStart}`);
    console.log(`Keydown. Selection end: ${element.selectionEnd}`);
})
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Test</title>

    <meta name="viewport"
          id="viewport-meta-tag"
          content="width=device-width, initial-scale=1.0">
</head>
<body>
    <input id="test"
           type="text"
           value="test">

</body>
</html>


Solution

  • Regarding Keyboard events, the selection data can be retrieved on "keyup", not on "keydown": elInput.addEventListener("keyup", (event) => {

    But, why listen to the keyboard?

    Use the "selectionchange" event since there's other ways a text can be selected (mouse, finger, keyboard, dynamically, etc)

    const elInput = document.querySelector("#test");
    
    elInput.addEventListener("selectionchange", (ev) => {
      console.log(`${ev.type}. Selection start: ${elInput.selectionStart}`);
      console.log(`${ev.type}. Selection end: ${elInput.selectionEnd}`);
    });
    <input id="test" type="text" value="test">