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

Adam Zerner
  • 17,797
  • 15
  • 90
  • 156
  • Would [this](http://stackoverflow.com/questions/668720/how-do-i-shift-the-visible-text-in-a-narrow-input-element-to-see-the-cursor-at-th/668856#668856) link work? It's pure JS. – Jonathan Levine Apr 27 '15 at 15:27
  • You can simply refocus the textarea to bring it back to the cursor location in webkit browsers. Doesn't work in IE/Firefox though – Alec Gorge Apr 27 '15 at 15:32
  • @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. – Adam Zerner Apr 27 '15 at 15:35

4 Answers4

28
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/

Audi Nugraha
  • 640
  • 7
  • 7
  • 6
    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. – ishmaelMakitla Dec 03 '16 at 20:00
  • 2
    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 wrong – llamerr Feb 15 '17 at 19:40
  • 1
    @llamerr actually, it won't - given that you didn't loose the focus of the field, the cursor will remain in it's place – tomasz stryjewski May 25 '17 at 15:39
  • @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) – llamerr May 18 '18 at 13:54
  • This answer also works on text input after modifying the caret position by using `setSelectionRange` – Caleb Taylor Apr 08 '21 at 19:46
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.

Community
  • 1
  • 1
Adam Zerner
  • 17,797
  • 15
  • 90
  • 156
  • 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 ;-) – Markai Apr 27 '15 at 15:44
  • 7
    The `keypress` is irrelevant here, this works even if you comment out that line: http://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' });` ? – Han Seoul-Oh May 18 '16 at 22:41
5

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);
sigmaxf
  • 7,998
  • 15
  • 65
  • 125
  • 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 brief – Prakash Jadhav Aug 11 '21 at 10:52
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();
}
Manngo
  • 14,066
  • 10
  • 88
  • 110