react router on how to collapse the navbar on mobile when selecting the menu links

Viewed 1521

Any idea on how to collapse the navbar on mobile when selecting the menu link pages.

here is the codesandbox link, feel free to fork it.

https://codesandbox.io/s/it6lj

enter image description here

Thanks!

5 Answers

I ran into this issue using Reactstrap 9.0.0-2 (based on Bootstrap 5.1.0 css library). I'm not sure if it was a problem with earlier (more stable) releases. Already had an idea in mind of how to get the menu to close on NavLink select, but wanted to see how other people solved the problem for some new ideas and experiences.

I tried the first accepted answer, adding the data-attributes and data-target on the NavLinks, and pointing at a css #id attribute on the NavbarToggler. This didn't work for me, unfortunately.

Instead, I solved the issue by setting up a click handler for the <NavLink /> tags, independent of the handler that toggles the menu. Unlike the other handler that opens and closes the menu, the NavLink handler only closes it by directly setting the menu's state object to false.

The logic goes: the menu has to be open in order to click on the <NavLink />, so this NavLink handler does not need to open the menu. And once you've made your choice about where you'd like to go, and have clicked on a Navlink tag, you'd probably like the menu to close and get out of your way, rather than having to close it yourself manually.

  • Simplified example:
import React, { useState } from 'react';
import { Collapse, Nav, NavBar, NarbarBrand, NavbarToggler, NavItem } from 'reactstrap';
import { NavLink } from 'react-router-dom';

const Header = (props) => {
    const [menuOpen, setMenuOpen] = useState(false);  // initially closed

    const toggleMenu = () => {     // this handler is "regular"
        setMenuOpen(!menuOpen);    // open and close...
    };

    const closeMenu = () => {      // ... and this one only
        setMenuOpen(false);    // closes it ...
    };

return (
  <NavBar expand="md">
    <Collapse isOpen={menuOpen} navbar>
      <Nav navbar>
        <NavLink
          to="/blog/:article"
          className="navlink text-light shadow-lg"
          onClick={closeMenu}
         >
          {blogArticle.title}
          </NavLink>
                     // . . . and so on . . .   

Sometimes the simplest solutions are also the best...

Add data-toggle="collapse" and data-target="#navbarCollapse" to each NavLink to also toggle closed the menu.

<ul className="navbar-nav ml-auto">
  <li className="nav-item">
    <NavLink
      data-toggle="collapse"
      data-target="#navbarCollapse"
      className="nav-link"
      activeClassName="active"
      to="/"
      exact
    >
      Home
    </NavLink>
  </li>
  <li className="nav-item">
    <NavLink
      data-toggle="collapse"
      data-target="#navbarCollapse"
      className="nav-link"
      activeClassName="active"
      to="/about"
    >
      About
    </NavLink>
  </li>

Edit epic-microservice-hvmlf

you can manage the menu visibility using a state:

import { useState } from "react";
import { NavLink } from "react-router-dom";

const Navbar = () => {
  const [show, setShow] = useState(false);
  const handleNavClick = () => {
    setShow(false);
  };
  return (
    <nav className="navbar navbar-expand-md navbar-dark bg-dark">
      <a className="navbar-brand" href="/">
        Fixed navbar
      </a>
      <button
        className="navbar-toggler"
        type="button"
        onClick={() => setShow(!show)}
      >
        <span className="navbar-toggler-icon" />
      </button>
      <div
        className={`collapse navbar-collapse  ${show ? "show" : ""}`}
        id="navbarCollapse"
      >
        <ul className="navbar-nav ml-auto">
          <li className="nav-item">
            <NavLink
              onClick={handleNavClick}
              className="nav-link"
              activeClassName="active"
              to="/"
              exact
            >
              Home
            </NavLink>
          </li>
          <li className="nav-item">
            <NavLink
              onClick={handleNavClick}
              className="nav-link"
              activeClassName="active"
              to="/about"
            >
              About
            </NavLink>
          </li>
        </ul>
      </div>
    </nav>
  );
};

export default Navbar;

You can use useRef hook for this and handle the class attribute of the div.

  const collapseRef = useRef(null);

  const hideBars = () => {
    collapseRef.current.setAttribute("class", "navbar-collapse collapse");
  };

  <div
    className="collapse navbar-collapse"
    id="navbarCollapse"
    ref={collapseRef}
  >

and then in your NavLink

        <NavLink
          className="nav-link"
          activeClassName="active"
          to="/about"
          onClick={hideBars}
        >
          About
        </NavLink>

Check this sandbox

if some still have this issue in bootsrap 5 just add these props to the li tag like this:

 <li className="nav-item" data-bs-toggle='collapse' data-bs-target='.navbar-collapse.show'>
      <Link className="nav-link" to="/">
        <img src={homepage_icon} className='nav-item-icon' />
        <h6>Page d'accueil</h6>
      </Link>

and you end up by collapsing navbar

Related