NextJS and bootstrap mobile nav

Viewed 384

I'm using bootstrap with NextJS for my navbar but have one issue because of the dynamic page changes with React and Next on mobile view the menu stays open after clicking a link and loading new page.

Tried a few ways to try and make it close on page changes but been unsuccessful. What would be best way to achieve this?

import { useEffect } from 'react'
import Link from 'next/link'
import Image from 'next/image'
import { ArrowDownCircle } from 'react-bootstrap-icons'
import logo from '../public/images/logo.gif'
import styles from '../styles/Navbar.module.scss'

const Navbar = () => {
    useEffect(() => {
        import('bootstrap/js/dist/collapse')
        import('bootstrap/js/dist/dropdown')
    }, []);

    return (
        <nav id="navbar" className="navbar navbar-expand-md navbar-light container">
            <div>
                <Link href="/" prefetch={false}><a className="navbar-brand">

                    <Image
                        src={logo}
                        alt="Logo"
                        layout="intrinsic"
                        width={200}
                        height={50}
                        priority={true}
                    />

                </a></Link>
            </div>

            <button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
                <span className="navbar-toggler-icon"></span>
            </button>

            <div className="collapse navbar-collapse" id="navbarNav">

                <ul className={`${styles.navLink} navbar-nav ms-auto`}>
                    <li className="nav-item">
                        <Link href="/" prefetch={false}><a className={`${styles.link} nav-link`} aria-current="page">Home</a></Link>
                    </li>
                    <li className="nav-item">
                        <Link href="/about" prefetch={false}><a className={`${styles.link} nav-link`}>About</a></Link>
                    </li>
                    <li className="nav-item dropdown">
                        <a className={`${styles.link} nav-link`} id="navbarDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false">Services <ArrowDownCircle className="ms-1" /></a>
                        <ul className="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
                            <li><Link href="/web-design"><a className="dropdown-item">Web Design</a></Link></li>
                            <li><Link href="/web-development"><a className="dropdown-item">Web Development</a></Link></li>
                            <li><Link href="/ecommerce"><a className="dropdown-item">eCommerce</a></Link></li>
                        </ul>
                    </li>
                    <li className="nav-item">
                        <Link href="/faq" prefetch={false}><a className={`${styles.link} nav-link`}>FAQ</a></Link>
                    </li>
                    <li className="nav-item">
                        <Link href="/contact" prefetch={false}><a className={`${styles.link} nav-link`}>Contact</a></Link>
                    </li>
                </ul>
            </div>

            <style jsx>{`
            a {
                background: none;
            }
            a:hover {
                background: none;
            }
            `}</style>
            
        </nav>
    );
}

export default Navbar;
1 Answers

If anyone still looking for solution in 2022 or later, follow these steps:

Note: This solution was tested on NextJs (Typescript) + Bootstrap v.5.2

  1. Add an id to the button with class navbar-toggler i.e. <button id="navbar-toggler" className="navbar-toggler" ...

  2. In your component class, say Header.tsx

Import useRouter and useEffect:

import { useRouter } from 'next/router'
import { useEffect } from 'react'

and within your component function:

const Header = () => {

    const router = useRouter()

    useEffect(() => {
        const handleRouteChange = (url: String) => {
            if (typeof window !== undefined && window.screen.width <= 991.98) { // change the width value according to your navbar breakpoint
                const navbar = document.getElementById("navbar-toggler");
                if (navbar !== null && !navbar.classList.contains('collapsed')) navbar.click()
            }
        }
        router.events.on('routeChangeComplete', handleRouteChange)
    }, [router.events])

    return (<> ... other codes </>)

}

export default Header
Related