78

I'm dynamically adding rows to a table using jQuery. The table is inside a div which has overflow:auto thus causing a vertical scrollbar.

I now want to autoscroll my container div to the last row. What's the jQuery version of tr.scrollintoView()?

sudo bangbang
  • 27,127
  • 11
  • 75
  • 77
Fuxi
  • 7,611
  • 25
  • 93
  • 139
  • 10
    As per [this answer](http://stackoverflow.com/questions/68165/javascript-to-scroll-long-page-to-div), this is apparently a built-in DOM function supported in all major browsers. Simply `element.scrollIntoView()` will work. – Kirk Woll May 29 '11 at 20:08

13 Answers13

88

This following works better if you need to scroll to an arbitrary item in the list (rather than always to the bottom):

function scrollIntoView(element, container) {
  var containerTop = $(container).scrollTop(); 
  var containerBottom = containerTop + $(container).height(); 
  var elemTop = element.offsetTop;
  var elemBottom = elemTop + $(element).height(); 
  if (elemTop < containerTop) {
    $(container).scrollTop(elemTop);
  } else if (elemBottom > containerBottom) {
    $(container).scrollTop(elemBottom - $(container).height());
  }
}
Abhijit Rao
  • 1,316
  • 1
  • 9
  • 13
  • 9
    This, sir, is not just an answer, it's a solution. Thank you. – witttness Oct 04 '10 at 22:51
  • 1
    You can remove the container argument and replace it with var container = element.offsetParent;... – Laurens Holst Feb 03 '11 at 11:28
  • 3
    @Laurens: That only works if the scrollable element is the direct parent of the child object. A more robust solution would be to iterate up its ancestry until it finds an element where .css("overflow") returns "auto" or "scroll". – Robert J. Walker Jun 06 '11 at 22:46
  • 3
    shouldn't your forth line be var elemTop = element.get(0).offsetTop ? The code didn't work till I did that. – Jacques Jul 10 '12 at 11:15
  • Also just discovered the Safari/Chrome scroll the container as well as the entire page as well. Anyone know of a way to stop that from happening? – Jacques Jul 10 '12 at 11:33
  • Should line 3 of this function: var elemTop = element.offsetTop; be changed to var elemTop = $(element).offset().top; ? – Daniel Rehner Aug 08 '12 at 19:56
  • 2
    While this solution almost works, it has serious problems. One is the typo, but more serious is the fact it does not deal gracefully with items that have any height. The better solution is the plugin from @Robert Koritnik – boatcoder Nov 16 '12 at 03:19
83
var rowpos = $('#table tr:last').position();

$('#container').scrollTop(rowpos.top);

should do the trick!

Gausie
  • 4,291
  • 1
  • 25
  • 36
29

Plugin that scrolls (with animation) only when required

I've written a jQuery plugin that does exactly what it says on the tin (and also exactly what you require). The good thing is that it will only scroll container when element is actually off. Otherwise no scrolling will be performed.

It works as easy as this:

$("table tr:last").scrollintoview();

It automatically finds closest scrollable ancestor that has excess content and is showing scrollbars. So if there's another ancestor with overflow:auto but is not scrollable will be skipped. This way you don't need to provide scrollable element because sometimes you don't even know which one is scrollable (I'm using this plugin in my Sharepoint site where content/master is developer independent so it's beyond my control - HTML may change when site is operational so can scrollable containers).

Robert Koritnik
  • 103,639
  • 52
  • 277
  • 404
  • This one really does work. Tried to fix the one from @Abhijit Rao to work, but it has lots of problems. This one just works. – boatcoder Nov 16 '12 at 03:17
  • @Mark0978: But be advised that I have to update it to work correctly with jQuery 1.8+ Custom selector definition has to be done differently with 1.8+. – Robert Koritnik Nov 16 '12 at 09:31
  • 1
    Got the plugin from GitHub and works smoothly as promised. Great job! – Youp Bernoulli Dec 15 '14 at 22:10
  • four year since update and this plugin still works like a charm. I used it in a angular directive :) – Shaunak Jan 13 '15 at 23:04
  • 1
    Four years later the plugin does not work for me--sometimes misses the mark with target almost but not in view. Today, assuming target is just one element, I use javascript: `var target = $(selector); target.get(0).scrollIntoView();` – subsci May 15 '15 at 07:12
  • Best solution! Clear, easy and elegant. – MarcM Dec 19 '16 at 12:59
20

much simpler:

$("selector for element").get(0).scrollIntoView();

if more than one item returns in the selector, the get(0) will get only the first item.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
Mor Shemesh
  • 2,689
  • 1
  • 24
  • 36
  • this would affect the scrolling of the page as well. So it wouldn't work. – Jacques Jul 10 '12 at 11:34
  • This doesn't do animation, nor does it deal with scrolling inside a scrollable div. – boatcoder Nov 16 '12 at 03:15
  • This doesn't do animation, but I find animated solutions failing in my particular use case which has an incredibly long element. The animated solutions sometimes miss the mark by a small offset. @Mark0978 my use case is a scrollable div--not sure why it works in my case but not yours – subsci May 15 '15 at 07:15
6

This runnable example shows how to use scrollIntoView() which is supported in all modern browsers: https://developer.mozilla.org/en-US/docs/Web/API/Element.scrollIntoView#Browser_Compatibility

The example below uses jQuery to select the element with #yourid.

$( "#yourid" )[0].scrollIntoView();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p id="yourid">Hello world.</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
Barry Staes
  • 3,890
  • 4
  • 24
  • 30
3
var elem=jQuery(this);
elem[0].scrollIntoView(true);
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
zuckerhut
  • 41
  • 1
3

If you just want to scroll, you could use jQuery's scrollTop method. http://docs.jquery.com/CSS/scrollTop

var table = jQuery( 'table' );
table.scrollTop( table.find( 'tr:last' ).scrollTop() );

Something like that maybe?

William
  • 15,465
  • 8
  • 36
  • 32
2

I found a case (overflow div > table > tr > td) in which scrolling to the relative position of the tr does not work. Instead, I had to scroll the overflow container (div) using scrollTop to <tr>.offset().top - <table>.offset().top. Eg:

$('#container').scrollTop( $('#tr').offset().top - $('#td').offset().top )
user1338062
  • 11,939
  • 3
  • 73
  • 67
2

Same from above with little modification

function focusMe() {
       var rowpos = $('#FocusME').position();
        rowpos.top = rowpos.top - 30;
        $('#container').scrollTop(rowpos.top);
    }
<html>
<script src="https://code.jquery.com/jquery-3.1.0.min.js" integrity="sha256-cCueBR6CsyA4/9szpPfrX3s49M9vUU5BgtiJj06wt/s=" crossorigin="anonymous"></script>
<body>
    <input type="button" onclick="focusMe()" value="focus">
    <div id="container" style="max-height:200px;overflow:scroll;">
        <table>
            <tr>
                <td>1</td>
                <td></td>
            </tr>
            <tr>
                <td>2</td>
                <td></td>
            </tr>
            <tr>
                <td>3</td>
                <td></td>
            </tr>
            <tr>
                <td>4</td>
                <td></td>
            </tr>
            <tr>
                <td>5</td>
                <td></td>
            </tr>
            <tr>
                <td>6</td>
                <td></td>
            </tr>
            <tr>
                <td>7</td>
                <td></td>
            </tr>
            <tr>
                <td>8</td>
                <td></td>
            </tr>
            <tr>
                <td>9</td>
                <td></td>
            </tr>
            <tr id="FocusME">
                <td>10</td>
                <td></td>
            </tr>
            <tr>
                <td>11</td>
                <td></td>
            </tr>
            <tr>
                <td>12</td>
                <td></td>
            </tr>
            <tr>
                <td>13</td>
                <td></td>
            </tr>
            <tr>
                <td>14</td>
                <td></td>
            </tr>
            <tr>
                <td>15</td>
                <td></td>
            </tr>
            <tr>
                <td>16</td>
                <td></td>
            </tr>
            <tr>
                <td>17</td>
                <td></td>
            </tr>
            <tr>
                <td>18</td>
                <td></td>
            </tr>
            <tr>
                <td>19</td>
                <td></td>
            </tr>
            <tr>
                <td>20</td>
                <td></td>
            </tr>
        </table>
    </div>
</body>

</html>
Arun Prasad E S
  • 9,489
  • 8
  • 74
  • 87
1

$( "#yourid" )[0].scrollIntoView();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p id="yourid">Hello world.</p>
<p>..</p>
<p>..</p>
<p>..</p>
<p>..</p>
Ajay Ram
  • 11
  • 1
0

I couldn't add a comment to Abhijit Rao's answer above, so I am submitting this as an additional answer.

I needed to have the table column scroll into view on a wide table, so I added the scroll left features into the function. As someone mentioned, it jumps when it scrolls, but it worked for my purposes.

function scrollIntoView(element, container) {
  var containerTop = $(container).scrollTop();
  var containerLeft = $(container).scrollLeft();
  var containerBottom = containerTop + $(container).height();
  var containerRight = containerLeft + $(container).width();

  var elemTop = element.offsetTop;
  var elemLeft = element.offsetLeft;
  var elemBottom = elemTop + $(element).height();
  var elemRight = elemLeft + $(element).width();

  if (elemTop < containerTop) {
    $(container).scrollTop(elemTop);
  } else if (elemBottom > containerBottom) {
    $(container).scrollTop(elemBottom - $(container).height());
  }

  if(elemLeft < containerLeft) {
    $(container).scrollLeft(elemLeft);
  } else if(elemRight > containerRight) {
    $(container).scrollLeft(elemRight - $(container).width());
  }
}
wuijin
  • 19
  • 2
0

Here is my stab at it and it's my working solution for my project.

function scrollToView($elem) {
  var $parent = $elem.parent();
  $parent.scrollTop(0);// reset parent scroll to calculate element's current position
  var viewH = $parent.height()-$elem.height();// calculate viewing pane height
  var elemTop = $elem.position().top;
  var viewMultiplier = Math.floor( elemTop / viewH); // calculate view multiplier
  $parent.scrollTop(viewMultiplier * viewH);
}
n00bdev
  • 1
  • 1
0

here is an example of scrolling to the row you want

function scrollToPositionTableRow(container, elementFirst, elementYouWantScroll) {
  var rowpos = $(elementYouWantScroll).position();
  var tableHeader = $($(elementFirst)).outerHeight();
  $(container).scrollTop(rowpos.top - tableHeader);
}
Tyler2P
  • 2,324
  • 26
  • 22
  • 31
nhoxhocju
  • 11
  • 2