Sticky element on a scroll in React
If you want to add a sticky div or paragraph on page scroll then today we will show you how to add a sticky element on a scroll in React. Here, we will not use any NPM Package to achieve this functionality.
Checkout more articles on ReactJS
- How to create tabs in React
- How to validate a checkbox list in React
- How to render HTML in React
- MultiSelect dropdown in React
- Implement idle timeout popup in React
Output
For demostration, we will add the sticky sidebar on page scroll.
Output - Sticky element on a scroll in React - Clue Mediator
Steps to add a sticky element on a scroll
1. Create a react application
Let’s create a React application using the `create-react-app` and render a component that contains the sidebar along with the content.
App.js
import React, { useState } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
function App() {
const [sidebarWidth, setSidebarWidth] = useState(undefined);
return (
<div class="app">
<h3>Sticky element on a scroll in React - <a href="https://www.cluemediator.com" target="_blank" rel="noreferrer noopener">Clue Mediator</a></h3>
<div class="row">
<div class="col-8">
{[...Array(20)].map((a, i) => (
<div key={i} class="item">
Lorem Ipsum is simply dummy text of the printing and typesetting
industry. Lorem Ipsum has been the industry's standard dummy text
ever since the 1500s.
</div>
))}
</div>
<div class="col-4">
<div class="sidebar" style={{ width: sidebarwidth }}>
<h3>Sidebar</h3>
<p>
Lorem Ipsum is simply dummy text of the printing and typesetting
industry. Lorem Ipsum has been the industry's standard dummy text
ever since the 1500s.
</p>
</div>
</div>
</div>
</div>
);
}
export default App;
2. Add a listener for the sticky element
In the next step, we will add a listener for the sticky element. On page scroll, we will add/remove `is-sticky` class to the sidebar.
const [sidebarWidth, setSidebarWidth] = useState(undefined);
const [sidebarTop, setSidebarTop] = useState(undefined);
useEffect(() => {
const sidebarEl = document.querySelector('.sidebar').getBoundingClientRect();
setSidebarWidth(sidebarEl.width);
setSidebarTop(sidebarEl.top);
}, []);
useEffect(() => {
if (!sidebarTop) return;
window.addEventListener('scroll', isSticky);
return () => {
window.removeEventListener('scroll', isSticky);
};
}, [sidebarTop]);
const isSticky = (e) => {
const sidebarEl = document.querySelector('.sidebar');
const scrollTop = window.scrollY;
if (scrollTop >= sidebarTop - 10) {
sidebarEl.classList.add('is-sticky');
} else {
sidebarEl.classList.remove('is-sticky');
}
}
Add the following CSS.
index.css
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
h1,
p,
div {
font-family: Lato;
padding: 10px;
}
.item {
border: 1px solid #ddd;
border-radius: 5px;
padding: 10px;
margin-bottom: 10px;
}
.sidebar {
border: 1px solid #ddd;
border-radius: 5px;
padding: 10px;
}
.is-sticky {
position: fixed;
top: 10px;
z-index: 999;
animation: 500ms ease-in-out 0s normal none 1 running fadeInDown;
}
3. Output
Let’s put all the code together and see how it looks.
App.js
import React, { useEffect, useState } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
function App() {
const [sidebarWidth, setSidebarWidth] = useState(undefined);
const [sidebarTop, setSidebarTop] = useState(undefined);
useEffect(() => {
const sidebarEl = document.querySelector('.sidebar').getBoundingClientRect();
setSidebarWidth(sidebarEl.width);
setSidebarTop(sidebarEl.top);
}, []);
useEffect(() => {
if (!sidebarTop) return;
window.addEventListener('scroll', isSticky);
return () => {
window.removeEventListener('scroll', isSticky);
};
}, [sidebarTop]);
const isSticky = (e) => {
const sidebarEl = document.querySelector('.sidebar');
const scrollTop = window.scrollY;
if (scrollTop >= sidebarTop - 10) {
sidebarEl.classList.add('is-sticky');
} else {
sidebarEl.classList.remove('is-sticky');
}
}
return (
<div class="app">
<h3>Sticky element on a scroll in React - <a href="https://www.cluemediator.com" target="_blank" rel="noreferrer noopener">Clue Mediator</a></h3>
<div class="row">
<div class="col-8">
{[...Array(20)].map((a, i) => (
<div key={i} class="item">
Lorem Ipsum is simply dummy text of the printing and typesetting
industry. Lorem Ipsum has been the industry's standard dummy text
ever since the 1500s.
</div>
))}
</div>
<div class="col-4">
<div class="sidebar" style={{ width: sidebarwidth }}>
<h3>Sidebar</h3>
<p>
Lorem Ipsum is simply dummy text of the printing and typesetting
industry. Lorem Ipsum has been the industry's standard dummy text
ever since the 1500s.
</p>
</div>
</div>
</div>
</div>
);
}
export default App;
Run the application and check the output in the browser.