Reputation: 113
I'm trying to add the sticky navbar effect to the navbar of a site when a user scrolls down. i.e I want the navbar to become fixed at the top of the page when the browser is scrolled down a certain height
I'm trying to implement this with react hooks. Here's the code for the navbar
Navbar.js
import { useEffect, useState } from "react";
const NavBar = () => {
// sticky nav
const [stickyClass, setStickyClass] = useState("");
function stickNavbar() {
let windowHeight = window.scrollY;
setStickyClass("sticky-nav") ? windowHeight > 500 : setStickyClass("");
}
useEffect(() => {
window.addEventListener("scroll", stickNavbar);
}, []);
return (
<nav className="relative w-full p-4">
<div className={`flex w-full flex-row items-center justify-between ${stickyClass}`}>
navbar content goes here ....
<div/>
<nav/>
I'm using tailwindcss for styling so there's no external stylesheet, however the sticky-nav
class applies some of tailwindcss's utility classes.
components.css
/* Navbar */
.sticky-nav {
@apply fixed top-0 left-0 w-full shadow-md z-20;
}
I did research it online but nothing really helpful came up, really hoping anyone could help me out here :) .
Upvotes: 8
Views: 27384
Reputation: 313
Here you can find a implementation of it in the most simplest way without using any external libraries or bootstrap. It even works with dynamic size of the navbar itself. This implementation uses a JSX file and a css file which is saved in the same directory under following name: navbar.module.css
.
The styling provided in this file is:
/* Only for setting up the element */
.navbarOffset {
padding: 10em;
}
/* Only for styling */
.content {
background-color: #333;
padding: 0.25em 1em 0.25em 1em;
}
/* Fix the navbar to the screen to create the sticky effect */
.sticky {
position: fixed;
}
You may will come into trouble where the navbar is "behind" the scrollbar. The reason for this is that you need to define box-sizing: border-box;
in order to work as intended.
import React, { useEffect, useState, useRef } from "react";
// Import the stylesheets
import styles from 'navbar.module.css'
const StickyNavbar = () => {
// All states
const [sticky, setSticky] = useState(false);
const [navHeight, setNavHeight] = useState(0);
// All refs
const navbar = useRef();
const navbarOffset = useRef();
// Mount the Event Listener on loading the site
useEffect(() => {
const handleScroll = () => {
// Get the offset to the top
const value = navbarOffset.current.clientHeight;
// Set the boolean value
setSticky(window.pageYOffset >= value);
}
window.addEventListener('scroll', handleScroll);
// Set the height of the Navbar
setNavHeight(navbar.current.clientHeight);
// Remove the listener when cleaning up
return () => window.removeEventListener('scroll', handleScroll);
}, []);
return (
<>
<div ref={navbarOffset}>This is the element before!</div>
{/* Always add the content class and only if it is sticky the other class */}
<div ref={navbar} className={`${styles.content} ${sticky && styles.sticky}`}>
I'm the content of the Navbar
</div>
{/* To prevent the next content to "jump" behind the navbar */}
<div style={sticky ? ({ marginTop: navHeight }) : ({})}></div>
</>
)
}
export default StickyNavbar;
I hope this can help you! For more questions I'm free to ask!
Upvotes: 0
Reputation: 1747
Try this :
import React, { useState, useEffect } from 'react';
export default function Navbar() {
const [stickyClass, setStickyClass] = useState('relative');
useEffect(() => {
window.addEventListener('scroll', stickNavbar);
return () => {
window.removeEventListener('scroll', stickNavbar);
};
}, []);
const stickNavbar = () => {
if (window !== undefined) {
let windowHeight = window.scrollY;
windowHeight > 500 ? setStickyClass('fixed top-0 left-0 z-50') : setStickyClass('relative');
}
};
return <div className={`h-16 w-full bg-gray-200 ${stickyClass}`}>Navbar</div>;
}
Demo (without Tailwinds but same result): Stackblitz
Upvotes: 7