iAdjunct
iAdjunct

Reputation: 2999

Javascript scrollIntoView only in immediate parent

How do I make scrollIntoView only scroll the immediate parent (e.g. div with overflow-y: scroll;) and not the whole page?

I have a web interface I'm making for an internal, very-specific purpose. Among other elements on my page is a div with a specified height and overflow-y is scroll.

I have data which will periodically appear in this area and I want it to always be scrolled to the bottom (e.g. the console output of a subprocess on some remote server).

If I use scrollIntoView, it scrolls the overflow-y div..... but also scrolls the whole page.

On a computer with a large monitor, this isn't an issue, but on my laptop with a smaller screen it also scrolls the whole window, which is definitely not the intended/desired behavior.

Upvotes: 52

Views: 28502

Answers (5)

Soham Bhattacharjee
Soham Bhattacharjee

Reputation: 1

You can also do this to reset the window to the position it was before, once the item is scrolled into view (in React).

const y = window.scrollY;
const x = window.scrollX;
if (isFocused && item.current) {
  item.current.scrollIntoView({ block: 'center' });
}
window.scroll(x, y);

Upvotes: -2

Iain Ballard
Iain Ballard

Reputation: 4828

I think what you might be looking for is

.scrollIntoView({block: "nearest", inline: "nearest"});

Where supported (basically anywhere except IE and SafarIE) this will do the 'least' movement to show the element; so if the outer container is visible, but the target element is hidden inside that container -- then it should scroll the inner container but not the page.

Upvotes: 71

foureyedraven
foureyedraven

Reputation: 337

Solution for React 16

Here is an answer for this problem using React 16, for people who want to have a scrollable element scroll to its bottom upon some event. I was having the problem that scrollIntoView() was causing the whole window to adjust, which was undesirable; just need the scrolling element to scroll to the bottom (like a terminal) on demand.

Add a ref to the element with overflowY: "scroll", and use the formula this.body.current.scrollTo(0, this.body.current.scrollHeight) like so:

constructor() {
    ...
    this.body = React.createRef() // Create a ref to your scrollable element
}
...

componentDidUpdate(prevProps, prevState) { // or whatever action you want
    // The Important Part, where you scroll to the y-coord 
    // that is the total height, aka the bottom. 
    // .current is important, as you want the version of 
    // that ref that is rendered right now.
    this.body.current.scrollTo(0, this.body.current.scrollHeight) 
    ...
}
...
render() {
   return (
      <div style={style.container}>
            <div ref={this.body} style={style.body}> // React ref tagged here
            ....
            </div>
    </div>
}

Upvotes: 1

Evgeny Melnikov
Evgeny Melnikov

Reputation: 1092

I tried to reproduce your case and I think that scrollIntoView() will not work as you wish. Try to use scrollTop instead. Hope it will save your time.

const btn = document.getElementById('js-scroll');

btn.addEventListener('click', () => {
  const targets = document.querySelectorAll('.scrollable');
  
  targets.forEach(t => {
    // Scroll each item
    t.scrollTop = t.scrollHeight;
  });
});
.scroll-btn {
  position:fixed;
  left: 10px;
  top: 10px;
  padding: 10px;
  font-weight: 700;
  font-size: 16px;
}
.content {
  min-height: 100vh;
  background-color: #efefef;
  padding: 35px 10px;
}

.scrollable {
  margin: 15px; 5px;
  padding: 5px;
  background-color: #fafafa;
  height: 500px;
  overflow-y: scroll;
  overflow-x: hidden;
}

.scrollable-data {
  padding: 10px;
  margin-bottom: 1px;
  min-height: 600px;
  background-color: #55b7ab;
}
<button id="js-scroll" class="scroll-btn">Scroll</button>

<section class="content">
  <div class="scrollable">
    <div class="scrollable-data">Some data 1</div>
    <div class="scrollable-data">Some data 1</div>
  </div>

  <div class="scrollable">
    <div class="scrollable-data">Some data 2</div>
    <div class="scrollable-data">Some data 2</div>
  </div>

  <div class="scrollable">
    <div class="scrollable-data">Some data 3</div>
    <div class="scrollable-data">Some data 3</div>
  </div>
</section>

Upvotes: 0

dbramwell
dbramwell

Reputation: 1326

I think you're looking for a combination of scrollTop and scrollHeight. You can use the first to set where you want the div to scroll to, and the second to get the height of all the info in the div:

var scrollyDiv = document.getElementById("container");
scrollyDiv.scrollTop = scrollyDiv.scrollHeight

setInterval(() => {
  var textnode = document.createElement("P");
  textnode.innerHTML = "Whatever"
  scrollyDiv.appendChild(textnode);  
  scrollyDiv.scrollTop = scrollyDiv.scrollHeight
}, 1000)
#container {
  height: 200px;
  overflow-y: scroll;
}

#big-content {
  height: 400px;
  background-color: green;
}
<div id="container">
  <div id="big-content"></div>
  <p>The bottom</p>
</div>

Upvotes: 4

Related Questions