11

I'm making a react app with tailwindcss, and I want to make a hidden mobile navbar and when the user click on the icon it appears.

So I want to make a transition while the menu appears.

I use:

  • React
  • Tailwindcss
  • Headlessui

My Code:

MobileMenu.js:

function MobileMenu() {
  return (
    <div className="block md:hidden px-4 py-3 text-white w-full bg-gray-800 border-t border-opacity-70 border-slate-700">
      <div className="flex items-center mb-3 pb-3 border-b border-slate-700">
        <img
          src="https://africaprime.com/wp-content/uploads/2020/04/ElonMusk.jpg"
          className="rounded-full w-8 h-8 cursor-pointer"
        />
        <h6 className="ml-5 cursor-pointer">Elon Musk</h6>
      </div>
      <div className="mobile-nav-icon">
        <ImHome size={20} />
        <h4 className="ml-5">Home</h4>
      </div>
      <div className="mobile-nav-icon">
        <HiUsers size={20} />
        <h4 className="ml-5">Friends</h4>
      </div>
      <div className="mobile-nav-icon">
        <CgProfile size={20} />
        <h4 className="ml-5">My Profile</h4>
      </div>
    </div>
  );
}

export default MobileMenu;

How I show it in Navbar.js:

function Navbar() {
  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
  return (
    <>
      <nav className="flex justify-between items-center px-4 lg:px-8 py-3 bg-gray-900 text-white">
        {/* Mobile Menu Icon */}
        <div
          className="block md:hidden p-2 cursor-pointer rounded-full hover:bg-gray-700 transition-2"
          onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
        >
          <FiMenu size={20} />
        </div>
      </nav>
      {/* Mobile Menu */}
      {mobileMenuOpen && <MobileMenu />}
    </>
  );
}

export default Navbar;

Thanks in advance!

M7md-Dev
  • 163
  • 1
  • 1
  • 13

2 Answers2

4

You can use @framer/motion package that allows you easily animate elements.

const menuVariants = {
    open: {
      opacity: 1,
      x: 0,
    },
    closed: {
      opacity: 0,
      x: '-100%',
    },
  }

Animations can be changed however you want according to @framer/motion docs.

And attach variants to your <MobileMenu /> component.

function MobileMenu({isMenuOpen}) {
  return (
    <motion.div animate={isMenuOpen ? 'open' : 'closed'}
    variants={menuVariants}> className="block md:hidden px-4 py-3 text-white w-full bg-gray-800 border-t border-opacity-70 border-slate-700">
      <div className="flex items-center mb-3 pb-3 border-b border-slate-700">
        <img
          src="https://africaprime.com/wp-content/uploads/2020/04/ElonMusk.jpg"
          className="rounded-full w-8 h-8 cursor-pointer"
        />
        <h6 className="ml-5 cursor-pointer">Elon Musk</h6>
      </div>
      <div className="mobile-nav-icon">
        <ImHome size={20} />
        <h4 className="ml-5">Home</h4>
      </div>
      <div className="mobile-nav-icon">
        <HiUsers size={20} />
        <h4 className="ml-5">Friends</h4>
      </div>
      <div className="mobile-nav-icon">
        <CgProfile size={20} />
        <h4 className="ml-5">My Profile</h4>
      </div>
    </div>
  );
}

export default MobileMenu;

And you can pass isMenuOpen variable as a prop.

function Navbar() {
  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
  return (
    <>
      <nav className="flex justify-between items-center px-4 lg:px-8 py-3 bg-gray-900 text-white">
        {/* Mobile Menu Icon */}
        <div
          className="block md:hidden p-2 cursor-pointer rounded-full hover:bg-gray-700 transition-2"
          onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
        >
          <FiMenu size={20} />
        </div>
      </nav>
      {/* Mobile Menu */}
      {mobileMenuOpen && <MobileMenu isMenuOpen={mobileMenuOpen}/>}
    </>
  );
}

export default Navbar;
schwarzsky
  • 80
  • 7
  • It doesn't work, I think because isMenuOpen prop is always true. – M7md-Dev Jul 14 '22 at 15:46
  • It doesn't make sense. You defined in `useState` as `false`. Only way to it can be `true` if you click the div using `setMobileMenuOpen(!mobileMenuOpen)` function. Be sure your MobileMenu's initial position is `l-[-100%] absolute`. If this not solves your problem, what is exactly happening on screen? – schwarzsky Jul 14 '22 at 16:09
  • it works normally without any transition, but when I log the isMenuOpen prop into console it always be true, but when log it form the parent components `Navbar.js` it will be false or true depends on the click. – M7md-Dev Jul 14 '22 at 16:16
  • I don't use relative and absolute method by the way – M7md-Dev Jul 14 '22 at 16:17
1

One potential issue with the provided answer is that state is not being set correctly. See the React Docs about updating state based on prior state value.

<div className="block md:hidden p-2 cursor-pointer rounded-full hover:bg-gray-700 transition-2" onClick={() => setMobileMenuOpen(prevState => !prevState)}>
Vbuongi
  • 26
  • 3