12

I have textarea and I want to change text that says what character is after the caret (cursor).

<textarea id="text"></textarea>
<br/>
Character after the caret: <span id="char"></span>

I know how to get caret position. The problem is I don't know what event is invoked when users movet the caret (by typing, pressing arrow keys, clicking, pasting text, cutting text, …).

jiwopene
  • 3,077
  • 17
  • 30
  • Can you explain the background of your problem? Someone could come up with a different solution to your, perhaps, *XY problem*. – Roko C. Buljan Jan 01 '19 at 22:21
  • maybe you could use one of the solutions in this post together with the change event of the textarea: https://stackoverflow.com/questions/7745867/how-do-you-get-the-cursor-position-in-a-textarea – kSp Jan 01 '19 at 22:25
  • @kSp Yes, I know how to do that. See my edit, please. – jiwopene Jan 01 '19 at 22:28

2 Answers2

17

I don't think there's a built-in event to check that, but you can use a combination of keypress, mousedown, and the other events that can trigger a caret position change, then check for changes to the textarea's selectionStart (which indicates caret position):

const textarea = document.querySelector('textarea');
textarea.addEventListener('keypress', checkcaret); // Every character written
textarea.addEventListener('mousedown', checkcaret); // Click down
textarea.addEventListener('touchstart', checkcaret); // Mobile
textarea.addEventListener('input', checkcaret); // Other input events
textarea.addEventListener('paste', checkcaret); // Clipboard actions
textarea.addEventListener('cut', checkcaret);
textarea.addEventListener('mousemove', checkcaret); // Selection, dragging text
textarea.addEventListener('select', checkcaret); // Some browsers support this event
textarea.addEventListener('selectstart', checkcaret); // Some browsers support this event

let pos = 0;
function checkcaret() {
  const newPos = textarea.selectionStart;
  if (newPos !== pos) {
    console.log('change to ' + newPos);
    pos = newPos;
  }
}
<textarea></textarea>
jiwopene
  • 3,077
  • 17
  • 30
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
6

There is an event for when the selection changes, selectionchange.

The selectionchange event is a global event, so listeners can be added on any element, although there is an experimental feature where event listeners on input elements and textarea elements only listen to changes in selection within that element. The experimental version is currently only supported in Firefox.

The selection can then be accessed through getSelection(). In a few browsers this will return undefined if the selection is inside an input or textarea element, so if getSelection() returns undefined, selectionStart and selectionEnd would work.

Example of the global selectionchange event:

let counter = 0;

document.addEventListener("selectionchange", function () {
  document.querySelector("#counter").textContent = ++counter;
})
<textarea>sample text</textarea>
<p>sample text in a paragraph</p>
<p contenteditable>a paragraph you can edit</p>

<p><code>selectionchange</code> events: <span id="counter">0</span></p>
jiwopene
  • 3,077
  • 17
  • 30
Manne
  • 61
  • 1
  • 3
  • *(Thank you very much for your answer.)* Well, since this is still experimental feature (and we usually do not expect that our users will use browser that is up-to-date, unless we are developing for something like intranet), it is not absolutely safe to use. But it is possible to combine this approach with [this one](https://stackoverflow.com/a/53999418/). – jiwopene Mar 07 '22 at 17:11
  • I thought it was worth adding to the thread anyway, since it is an easier approach if, for your purposes, you only care about newer browsers. – Manne Mar 09 '22 at 06:23
  • 1
    note: selectionchange doesn't trigger on backspace, enter, delete key, etc. – GorvGoyl Mar 09 '22 at 09:45
  • @Manne, of course, there is no problem in that. StackOverflow is a place that is quite open for finding better or alternative solutions to solved thing. – jiwopene Mar 09 '22 at 15:34