最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Tailwindcss showhide transition - Stack Overflow

programmeradmin0浏览0评论

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=".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!

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!

Share Improve this question asked Jul 14, 2022 at 14:55 M7md-DevM7md-Dev 1931 gold badge2 silver badges15 bronze badges
Add a comment  | 

3 Answers 3

Reset to default 6

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;

Your approach is to include or exclude the whole component depending on the visibility state, but a DOM structure change can't be animated. The right approach is to pick a CSS property of an existing element that can change gradually over time, like position and opacity. This solution uses only Tailwind means, no additional dependency for animation required.

As for TailwindCSS, the fundamental mechanics is to declare that CSS changes animate as transitions. Add the transition class for any change to animate, or pick out specific properties with transition-opacity or transition-transform. (The latter for scale, translate, rotate transformations.) Optionally, specify the duration time with duration-300, if the default of 150 doesn't fit.

The actual transition animation is kicked off by changing CSS properties, which means in Tailwind adding, removing, or replacing one or more classes.

This below is how this might look like. The code toggles animated properties based on the new passed-in prop visible, which comes from Navbar and its open button. Both opacity and a translation are animated as transitions. ease-out and ease-in are flipped as well depending on if the transition is going in or out.

// MobileMenu.js
import { ImHome } from "react-icons/im";
import { CgProfile } from "react-icons/cg";
import { HiUsers } from "react-icons/hi";
import { clsx } from "clsx";

function MobileMenu({ visible }) {
  return (
    <div
      className={clsx(
        "relative block px-4 py-3 text-white w-full bg-gray-800 border-t border-opacity-70 border-slate-700 flex flex-col space-y-5",
        "transition duration-200 -z-10 ease-out",
        {
          "ease-out": visible,
          "ease-in": !visible,
          "opacity-0": !visible,
          "opacity-100": visible,
          "-translate-y-full": !visible,
          "translate-y-0": visible,
        }
      )}
    >
      <div className="flex items-center pb-3 border-b border-slate-700">
        <img
          src="https://placehold.co/32x32"
          className="rounded-full w-8 h-8 cursor-pointer"
        />
        <h6 className="ml-5 cursor-pointer">Elon Musk</h6>
      </div>
      <div className="flex items-center">
        <ImHome size={20} />
        <h4 className="ml-5">Home</h4>
      </div>
      <div className="flex items-center">
        <HiUsers size={20} />
        <h4 className="ml-5">Friends</h4>
      </div>
      <div className="flex items-center">
        <CgProfile size={20} />
        <h4 className="ml-5">My Profile</h4>
      </div>
    </div>
  );
}

export default MobileMenu;
// Navbar.js
import React, { useState } from "react";
import { FiMenu } from "react-icons/fi";
import MobileMenu from "./MobileMenu";

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

export default Navbar;

Check out the running code as codesandbox.

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)}>
发布评论

评论列表(0)

  1. 暂无评论