To scroll to the bottom of a div
element in React:
- Create an element at the bottom of the
div
. - Set a ref on this element.
- Call
scrollIntoView()
on the ref to scroll down to this element.
import { useRef } from 'react';
const allFruits = [
'Apples',
'Bananas',
'Oranges',
'Grapes',
'Strawberries',
'Blueberries',
'Pineapples',
'Mangoes',
'Kiwis',
'Watermelons',
];
export default function App() {
const bottomEl = useRef(null);
const scrollToBottom = () => {
bottomEl?.current?.scrollIntoView({ behavior: 'smooth' });
};
return (
<div>
<div
style={{
position: 'fixed',
backgroundColor: 'white',
bottom: 0,
marginBottom: 10,
}}
>
<button onClick={scrollToBottom} style={{ marginLeft: '8px' }}>
Scroll to bottom
</button>
</div>
<div style={{ height: '5rem' }} />
<div>
{allFruits.map((fruit) => (
<h2 key={fruit}>{fruit}</h2>
))}
{/* 👇 Element created at the bottom */}
<div ref={bottomEl}></div>
</div>
<div style={{ height: '150rem' }} />
</div>
);
}
Here we have a list of fruits displayed.
The Scroll to bottom
button scrolls to the bottom of the div on click.
It does this by calling scrollIntoView()
in a click
event listener we set, on the bottom element’s ref.
const scrollToBottom = () => {
bottomEl?.current?.scrollIntoView({ behavior: 'smooth' });
};
We set the behavior
option to smooth
to make the element scroll into view in an animated way, instead of jumping straight to the element in the next frame – auto
.
auto
is the default.
We create the ref object with the useRef
hook and assign it to the ref
prop of the target div
element.
const bottomEl = useRef(null);
Doing this sets the current
property of the ref object to the DOM object that represents the element.
useRef
returns a mutable object that maintains its value when a component updates.
Also, modifying the value of this object’s current
property doesn’t cause a re-render.
This is unlike the setState
update function return from the useState
hook.
Scroll to bottom of dynamic list div in React
We can do something similar to scroll to the bottom of a div containing a list of items that change.
import { useRef, useState } from 'react';
const allFruits = [
'Apples',
'Bananas',
'Oranges',
'Grapes',
'Strawberries',
'Blueberries',
'Pineapples',
'Mangoes',
'Kiwis',
'Watermelons',
];
export default function App() {
const ref = useRef(null);
const [fruits, setFruits] = useState([...allFruits.slice(0, 3)]);
const addFruit = () => {
setFruits((prevFruits) => [...prevFruits, allFruits[prevFruits.length]]);
};
const scrollToLastFruit = () => {
const lastChildElement = ref.current?.lastElementChild;
lastChildElement?.scrollIntoView({ behavior: 'smooth' });
};
return (
<div>
<div
style={{
position: 'fixed',
backgroundColor: 'white',
bottom: 0,
marginBottom: 10,
}}
>
<button onClick={addFruit}>Add fruit</button>
<button onClick={scrollToLastFruit} style={{ marginLeft: '8px' }}>
Scroll to last
</button>
</div>
<div style={{ height: '5rem' }} />
<div ref={ref}>
{fruits.map((fruit) => (
<h2 key={fruit}>{fruit}</h2>
))}
</div>
<div style={{ height: '150rem' }} />
</div>
);
}
Like in the previous example, we also have a list of fruits displayed here.
But this time the list isn’t static – when can add an item to it with the Add fruit
button.
The Scroll to last
button scrolls to the last item in the div – the most recently added item.
Like before, we use the onClick
prop to set a click event listener on the button.
We set the ref on the list instead of a list item, since the items are created dynamically, and the last item will not always be the same.
Doing this sets the current
property of the ref object to the DOM object that represents the list element.
In this listener, we use the lastElementChild
property of the list element to get its last item element. Then we call scrollIntoView()
on this last item to scroll down to it.
const scrollToLastFruit = () => {
const lastChildElement = ref.current?.lastElementChild;
lastChildElement?.scrollIntoView({ behavior: 'smooth' });
};
Scroll to bottom of div after render
Sometimes we want to scroll to the bottom of the div immediately after the page renders.
Like if we want to scroll to the bottom of the list in the previous section,
we’ll just a useEffect()
hook and call scrollIntoView()
in the hook.
const scrollToLastFruit = () => {
const lastChildElement = ref.current?.lastElementChild;
lastChildElement?.scrollIntoView({ behavior: 'smooth' });
};
useEffect(() => {
scrollToLastFruit();
}, []); // 👈 empty deps array
The code in useEffect
is run after the component mounts.
And also when any value in the dependency array changes.
We pass an empty dependency array – so there are no dependencies.
So the useEffect
will only run when the component mounts.
Here’s the full code for reference:
import { useEffect, useRef } from 'react';
const allFruits = [
'Apples',
'Bananas',
'Oranges',
'Grapes',
'Strawberries',
'Blueberries',
'Pineapples',
'Mangoes',
'Kiwis',
'Watermelons',
];
export default function App() {
const ref = useRef(null);
const scrollToLastFruit = () => {
const lastChildElement = ref.current?.lastElementChild;
lastChildElement?.scrollIntoView({ behavior: 'smooth' });
};
useEffect(() => {
scrollToLastFruit();
}, []); // 👈 empty deps array
return (
<div>
<div style={{ height: '5rem' }} />
<div ref={ref}>
{allFruits.map((fruit) => (
<h2 key={fruit}>{fruit}</h2>
))}
</div>
<div style={{ height: '150rem' }} />
</div>
);
}
Key takeaways
- To scroll to the bottom of a div element in React, create a ref on the target element and use
scrollIntoView()
. - The
useRef
hook creates a mutable ref object that can be assigned to theref
prop. - Set the
behavior
option tosmooth
for a smooth scrolling animation. - For dynamic lists, set the ref on the container element and scroll to the last child element.
- To scroll to the bottom immediately after rendering, use
useEffect
with an empty dependency array. - The code within
useEffect
runs after mounting and when dependency values change.
11 Amazing New JavaScript Features in ES13
This guide will bring you up to speed with all the latest features added in ECMAScript 13. These powerful new features will modernize your JavaScript with shorter and more expressive code.