DEV Community

Cover image for Sticky navbar from scratch using react
Rohit Dalal
Rohit Dalal

Posted on

Sticky navbar from scratch using react

In many modern websites, you must have seen this effect of Navigation bar/ Header sticking to the top of the page even if you scroll down the page for your better navigation so you don’t have to go up always to choose between links for moving between the pages. Haven’t you?
If you have and are curious about how does that work, then this post is your go-to guide to create that very simple yet beautiful effect/feature for you next project which adds better UX to the page.
What are you waiting for? Let’s get started 🚀

Initial Setup

First, we are going to create a react-app from start. For that enter this command in your favourite terminal

create-react-app sticky-navbar
Enter fullscreen mode Exit fullscreen mode

We are going to delete some of the files created out of the box from create-react-app. After deleting some files, project directory will look like this:
Starting structure

We will start by creating components, two components will suffice for this little project. Create a directory called Components in /src and add two files Navbar.js and Content.js
Start by editing App.js. Add the following code to start with a basic layout

//App.js
import React from 'react';
import Navbar from './components/Navbar';
import Content from './components/Content';
function App() {
  return (
    <div className="App">
      <Navbar />
      <Content />
    </div>
  );
}
export default App;
Enter fullscreen mode Exit fullscreen mode

Here we are rendering two functional components Navbar and Content, their name clearly explains their purpose.
This below code fills up Navbar.js. Navbar component is basically a header section which consists of your website Logo and one navigation menu with 4/5 links

//Navbar.js
import React from 'react';
import './navbar.scss';
import Logo from './../img/logo.svg';
const Navbar=() => {
  return (
    <header className={navbarClasses.join(" ")}>

        <div className="logo">
            {/* your logo */}
        </div>
        <nav className="navigation">
            {/* your navigation */}
        </nav>

    </header>
  )
};
export default Navbar;
Enter fullscreen mode Exit fullscreen mode

Now, it’s time to give some styling to the page. You can have your own set of styling or if you just want to use mine, copy below given styles to navbar.scss

//navbar.scss
.navbar{
  width: 100%;
  min-height: 6vh;
  box-sizing: border-box;
  display: flex;
  justify-content: space-between;
  align-items: center;
  background-color: #eee;
  transition: all .7s ease-in;
}
//IMPORTANT
.scrolled{
  position: fixed;
  top: 0;
  left: 0;
  background-color: lightblue;
}
.logo img{
  width: 50px;
}
.navigation{
    //your navigation styles
}
Enter fullscreen mode Exit fullscreen mode

Now, we would fill up Content.js with some meat to add some content on the page along with the Navbar.
This code fills up dummy boxes to take ample amount of height on-page. You can use any real-life content. This is just for demo

//Content.js
import React from 'react';
import './content.scss';
const Content=() => {
  const data=(
    <div className="box">
        <h2>My div content </h2>
    </div>
  );
return (
    <main className="content">
        {data}
        {data}
        {data}
        {data}
        {data}
    </main>
  )
}
export default Content;
Enter fullscreen mode Exit fullscreen mode

Style for Content.js

//content.scss
.content{
    width: 80%;
    margin:2rem 10% 0 10%;
    max-width: 100%;
    box-sizing: border-box;
    min-height: 100vh;
}
.box{
    width:80%;
    margin:2rem 10% 0 10%;
    height:100vh;
    background-color:plum;
}
Enter fullscreen mode Exit fullscreen mode

After all this setup, our page will look like this:
Complete layout

Main Logic

Now that we have our meat set up for the Sticky navbar, we will add the main Logic to get that sticky effect. For this, we are going to do a little bit of state-management using React hooks. If you are not aware of react-hooks, don’t worry about it. You can use normal state management with classful component too.
So, the idea is as you scroll down, you check for the scrollY (i.e. total height you have scrolled from the top in pixels ) in componentDidMount() or useEffect() using window.scrollY and if that scrolled height is greater than some value, say 200px in this case, then we change the class of our Navbar to navbar scrolled. Styles for .scrolled is already in your navbar.scss if you have copied my styles. I have used array approach to switch between classes from navbar to navbar scrolled.

Confused?

//Navbar.js
import React,{useEffect} from 'react';
import './navbar.scss';
const Navbar=() => {
  const [scrolled,setScrolled]=React.useState(false);
const handleScroll=() => {
    const offset=window.scrollY;
    if(offset > 200 ){
      setScrolled(true);
    }
    else{
      setScrolled(false);
    }
  }

  useEffect(() => {
    window.addEventListener('scroll',handleScroll)
  })
let navbarClasses=['navbar'];
  if(scrolled){
    navbarClasses.push('scrolled');
  }

   return (
    /* rest remains same*/
   )
};
export default Navbar;
Enter fullscreen mode Exit fullscreen mode

In this way, we have successfully created our simple sticky Navbar from scratch.
If you want to look at the complete code, check my GitHub repo.

Conclusion

This was all for this simple demo application. I hope this post was helpful to you and I’ve solved your problem by explaining it in your words. If you have any queries regarding this post, feel free to ask me personally. I will be happy to answer those on an individual level.
Thank you. Have a nice day!

Top comments (20)

Collapse
 
madhavbahlmd profile image
MADHAV BAHL

Hi @rohit ,
Is there any codepen sample? Or somewhere you have hosted this code? Or GitHub repo?

Collapse
 
dalalrohit profile image
Rohit Dalal

Yes, @madhavbahlmd , I've given the GitHub link for the same at the end of the post.
Here is the link again: GitHub Repo

Sorry for the late reply!

Collapse
 
sum1275 profile image
sum1275

suppose along with navbar there is header to means navbar is the subset of header in header there is company logo and in navbar other components are there
like home,service etc.
now i want to keep only my navbar component static and header component not.
Then what to do .
please help me with some article or any code suggestion.

Thread Thread
 
dalalrohit profile image
Rohit Dalal

Hey sorry for the late reply,

Can you elaborate more clearly on the problem, please?
I'm quite not clear on the asked question.

Thank you,

Thread Thread
 
sum1275 profile image
sum1275

Hello buddy i attached an image that explain better.

Animated sticky header on scroll in React---this should be problem statement.

Thread Thread
 
dalalrohit profile image
Rohit Dalal

I don't see any image attached

Thread Thread
 
sum1275 profile image
sum1275

here see

Thread Thread
 
sum1275 profile image
sum1275

did you get ??

Collapse
 
arabsight profile image
Rabah Ghodbane • Edited

you should remove the event listener in the clean up function of useEffect to avoid memory leaks.
And provide an empty dependency array to useEffect to only register the event once when the component mounts.

Collapse
 
federerkristijan profile image
Kristijan Federer

thank you @rohit! worked amazing, need to adjust some overflow, but otherwise works like a charm!

Collapse
 
jer_developing profile image
Jeremy

Hi Rohit,

Thanks so much for this - I found it really helpful!

One slight change I made to my own code it I removed the navbarClasses (and the if block to push 'scrolled' onto the className and instead, in the function return, included the following: className={setScrolled? 'navbar scrolled' : 'navbar'} which seems like less overhead and transitions smoother (especially noticeable when you set the transition and conditional if block to check offset are both set to 0).

Collapse
 
dalalrohit profile image
Rohit Dalal

Thank you, Jeremy! Glad to hear you found it useful ;)

Yes, your approach to choosing appropriate className upon scroll is too perfect. No problem with it.

I just chose it for simplicity. Nothing else.

Happy coding :)

Collapse
 
utsavdh profile image
Utsav Dhungana

hey jeremy, can you provide the link to this code?

Collapse
 
kumar2106 profile image
Kumar2106

That was really a nice example to explain, can you please make another post on how we can align other component beneath the nav bar. Actually right now i am trying to code one react project in which i have to put my resume pdf beneath my navbar, but that is not happening.

Collapse
 
karem1986 profile image
Karem

Why do we need to use join() method? please explain:)

Collapse
 
dalalrohit profile image
Rohit Dalal

Hey Karem,

According to my approach, navbarClasses is an array of 2 strings. So, to make a single string from those, join() will make it happen.

console.log( ['navbar','scrolled'].join(" ") )  // "navbar scrolled"
Enter fullscreen mode Exit fullscreen mode

Another approach is to use Ternary operator like this:

className={scrolled ? 'navbar scrolled' : 'navbar'}
Enter fullscreen mode Exit fullscreen mode

I hope I've cleared it out ;)

Collapse
 
karem1986 profile image
Karem

Thanks Rohit! Great explanation :)

Collapse
 
battleofplassey profile image
Palash Shrivastava

Thanks Rohit. This helped a lot, I was stuck on a project (migrating HTML to NEXT.js) trying to run jquery to implement sticky header.

Collapse
 
dalalrohit profile image
Rohit Dalal

Glad you found it helpful :)

Good day ;)

Collapse
 
b33hazard profile image
MUHAMMAD ALI

Hello Rohit, this is awesome. but i'll go with ternary.