How do you scroll to the position of the cursor in a textarea?
Asked Answered
W

4

20

JS Fiddle Demo

HTML

<textarea rows='5'>
sdfasjfalsfjasf;klasdfklaksdfkjlasdfkjlasdjkfadls;fjklasdfjklasdkjlfaskljdfkalsjdfjlkasdfkjlasdkjlfasfkl;ajklsdfjklasdfkjlaskjldfaskjlfkljsadkjlfaskjldfkjlasdfkjlasdjklfaskljdfkjlasfkjlasdkjlfasjklfajklsdfjklasdfjlkadjsdfasjfalsfjasf;klasdfklaksdfkjlasdfkjlasdjkfadls;fjklasdfjklasdkjlfaskljdfkalsjdfjlkasdfkjlasdkjlfasfkl;ajklsdfjklasdfkjlaskjldfaskjlfkljsadkjlfaskjldfkjlasdfkjlasdjklfaskljdfkjlasfkjlasdkjlfasjklfajklsdfjklasdfjlkadjsdfasjfalsfjasf;klasdfklaksdfkjlasdfkjlasdjkfadls;fjklasdfjklasdkjlfaskljdfkalsjdfjlkasdfkjlasdkjlfasfkl;ajklsdfjklasdfkjlaskjldfaskjlfkljsadkjlfaskjldfkjlasdfkjlasdjklfaskljdfkjlasfkjlasdkjlfasjklfajklsdfjklasdfjlkadjsdfasjfalsfjasf;klasdfklaksdfkjlasdfkjlasdjkfadls;fjklasdfjklasdkjlfaskljdfkalsjdfjlkasdfkjlasdkjlfasfkl;ajklsdfjklasdfkjlaskjldfaskjlfkljsadkjlfaskjldfkjlasdfkjlasdjklfaskljdfkjlasfkjlasdkjlfasjklfajklsdfjklasdfjlkadj
</textarea>

<br />
<button id='scroll-to-cursor'>Scroll to Cursor</button>

JavaScript

$('#scroll-to-cursor').on('click', function() {
    // ?
});

Desired Outcome

  1. Click somewhere in the textarea to place cursor.
  2. Scroll away so cursor isn't visible.
  3. Click "Scroll to Cursor" button.
  4. Textarea scrolls to the position of the cursor

Note: I'm using jQuery.

The only way I could figure out how to scroll is to use jQuery's scrollTop function. It sets the scroll position to "the number of pixels that are hidden from view above the scrollable area".

I've diagrammed the problem below. Passing in the length of that red line (in pixels) to scrollTop should do the trick. But I can't figure out how to get the length of the line.

enter image description here

Wilfordwilfred answered 27/4, 2015 at 15:6 Comment(3)
Would this link work? It's pure JS.Arielle
You can simply refocus the textarea to bring it back to the cursor location in webkit browsers. Doesn't work in IE/Firefox thoughChallenge
@JonathanLevine it did work, thanks! On first glance I saw that it was for inputs and horizontal scrolling, so I didn't think it applied but I just tested it and it does work.Wilfordwilfred
W
7

From Jonathan Levine's comment, I realized that this answer works for me.

Fiddle Demo

JavaScript

$('#scroll-to-cursor').on('click', function() {    
    $('textarea').focus();
    $.event.trigger({ type : 'keypress' }); // works cross-browser

    // new KeyboardEvent('keypress'); // doesn't work in IE and Safari

    /* var evt = document.createEvent('KeyboardEvent');
    evt.initKeyEvent('keypress', true, true, null, false, false, false, false, 0, 32);
    $textarea.dispatchEvent(evt);

    evt = document.createEvent('KeyboardEvent');
    evt.initKeyEvent('keypress', true, true, null, false, false, false, false, 8, 0);
    $textarea.dispatchEvent(evt); */
});

/*
    To test:
    1) Click somewhere in the textarea to place cursor
    2) Scroll away so cursor isn't visible
    3) Click "Scroll to Cursor" button
*/

Explanation

When the user presses a key, the browser does two things:

  1. Places the key in the position after the cursor.
  2. Scrolls to that position.

This solution just simulates that (without actually entering any text).

Edit: The old solution isn't standards compliant. initKeyEvent is deprecated. The update only uses the KeyboardEvent() constructor, which is compliant and works in all browsers except IE (Safari is a question mark).

Edit 2: Using $.event.trigger({ type : 'keypress' }); instead of new KeyboardEvent() works just as well, and works in all browsers.

Wilfordwilfred answered 27/4, 2015 at 15:42 Comment(2)
I had the same idea with arrow right and arrow left, but yours is better because of arrow key usage would change cursor position on end of the text ;-)Crash
The keypress is irrelevant here, this works even if you comment out that line: jsfiddle.net/g74aabta What's happening is that clicking on the button is blurring the textarea, and re-focusing the textarea is scrolling the cursor into view. Didn't you think it was odd that the textarea isn't an argument to $.event.trigger({ type : 'keypress' }); ?Parse
I
31
textarea.blur()
textarea.focus()

Does the job.

Example: https://jsfiddle.net/syy25x69/

To select a text in IE see: Set textarea selection in Internet Explorer

Update

In order for this to work, I noticed that the selection must be collapsed. You can restore the selection later if you need to.

// collapse selection here
textarea.blur()
textarea.focus() // this scrolls the textarea
// expand selection here

Another example: https://jsfiddle.net/rk8cL174/

Impersonal answered 3/12, 2016 at 19:54 Comment(5)
Explain why this should work - this will also help the rest of the community to understand how you solved this problem/question. This is especially important for questions that already have accepted answers - it has to be clear why your answer should also be considered.Colorful
it will blur/focus textarea and put cursor to THE END of textarea, so it will scroll textarea to the end, not to the place of cursor. which is wrongSutphin
@Sutphin actually, it won't - given that you didn't loose the focus of the field, the cursor will remain in it's placeShaunta
@tomaszstryjewski it does work right now (at least on Mac in current Chrome), but at the time I tested it (Feb 15 2017 on Chrome on Linux) I believe it worked as I described (I was unable to easily find and download Chrome version for that day)Sutphin
This answer also works on text input after modifying the caret position by using setSelectionRangeMacymad
W
7

From Jonathan Levine's comment, I realized that this answer works for me.

Fiddle Demo

JavaScript

$('#scroll-to-cursor').on('click', function() {    
    $('textarea').focus();
    $.event.trigger({ type : 'keypress' }); // works cross-browser

    // new KeyboardEvent('keypress'); // doesn't work in IE and Safari

    /* var evt = document.createEvent('KeyboardEvent');
    evt.initKeyEvent('keypress', true, true, null, false, false, false, false, 0, 32);
    $textarea.dispatchEvent(evt);

    evt = document.createEvent('KeyboardEvent');
    evt.initKeyEvent('keypress', true, true, null, false, false, false, false, 8, 0);
    $textarea.dispatchEvent(evt); */
});

/*
    To test:
    1) Click somewhere in the textarea to place cursor
    2) Scroll away so cursor isn't visible
    3) Click "Scroll to Cursor" button
*/

Explanation

When the user presses a key, the browser does two things:

  1. Places the key in the position after the cursor.
  2. Scrolls to that position.

This solution just simulates that (without actually entering any text).

Edit: The old solution isn't standards compliant. initKeyEvent is deprecated. The update only uses the KeyboardEvent() constructor, which is compliant and works in all browsers except IE (Safari is a question mark).

Edit 2: Using $.event.trigger({ type : 'keypress' }); instead of new KeyboardEvent() works just as well, and works in all browsers.

Wilfordwilfred answered 27/4, 2015 at 15:42 Comment(2)
I had the same idea with arrow right and arrow left, but yours is better because of arrow key usage would change cursor position on end of the text ;-)Crash
The keypress is irrelevant here, this works even if you comment out that line: jsfiddle.net/g74aabta What's happening is that clicking on the button is blurring the textarea, and re-focusing the textarea is scrolling the cursor into view. Didn't you think it was odd that the textarea isn't an argument to $.event.trigger({ type : 'keypress' }); ?Parse
M
6

For some weird reason, Chrome only scrolls when there is a caret on the textbox, not when a selection is active, so if you need to scroll to a selection, do this little hack:

  // set the single caret first
  textarea.setSelectionRange(index, index);

  // focus the textarea box so the scroll happens
  textarea.focus();

  // now do the selection
  textarea.setSelectionRange(index, index + x);
Melodee answered 27/3, 2021 at 15:38 Comment(1)
Yeah this is 100% true when there is active selection cursor will be nowhere, so focus wont work. Above code worked for me thanks @sigmawf, for briefJemina
M
1

This is my spin on things.

I found that Audi Nugraha’s solution worked when testing, but not when I tried it in an Electron application.

A solution which did work for me was to position the cursor to the beginning and then blur/focus.

textarea.selectionEnd = textarea.selectionStart = position;
textarea.blur();
textarea.focus();

I have incorporated the above into a function:

function scrollTextarea(textarea,position) {
    textarea.selectionEnd = textarea.selectionStart = position;
    textarea.blur();
    textarea.focus();
}
Macaroni answered 30/5, 2019 at 6:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.