I would like to implement a transition with tailwincss , on 'active' state change, I mean when the menu is shown/collapsed i would like to implement a smooth and pleasing transition
I tried adding it on the state change by adding transition delay-150 duration-300 ease-in-out but i couldn't make it work.
import Link from "next/link";
import { useState } from "react";
import HamburgerMenu from "react-hamburger-menu";
import dynamic from "next/dynamic";
const NavLink = dynamic(() => import("./NavLink"));
export const Navbar = () => {
const [active, setActive] = useState(false);
const [isOpen, setIsOpen] = useState(false);
const handleClick = () => {
setActive(!active);
setIsOpen(!isOpen);
};
const handleClose = () => {
setActive(false);
setIsOpen(false);
};
return (
<nav className="sticky top-0 z-10 flex flex-wrap items-center px-3 py-3 bg-white md:py-3 container bg-red-200">
<div className="flex flex-wrap items-center justify-between w-full">
<Link href="/">
<a className="inline-flex items-center">
<span className="text-xl font-bold tracking-wide text-black tahu">
Agoumi.
</span>
</a>
</Link>
<div className="inline-flex p-0 ml-auto text-xl rounded-full outline-none hover:shadow-sm hover:bg-gray-100 hover:text-black">
<HamburgerMenu
isOpen={isOpen}
menuClicked={handleClick}
width={20}
height={15}
strokeWidth={2}
rotate={0}
color="black"
// borderRadius={15}
animationDuration={1}
className="m-3"
/>
</div>
</div>
<div
className={`${
active ? "transition delay-150 duration-300 ease-in-out" : "hidden"
} w-full`}
>
<div className="flex flex-col items-start w-full align-center">
<NavLink close={handleClose} to="/" linkName="Home" isOpen={false} />
<NavLink
close={handleClose}
to="about"
linkName="About Me"
isOpen={false}
/>
<NavLink
close={handleClose}
to="value"
linkName="Values"
isOpen={false}
/>
<NavLink
close={handleClose}
to="projects"
linkName="Projects"
isOpen={false}
/>
<NavLink
close={handleClose}
to="contact"
linkName="Contact us"
isOpen={false}
/>
</div>
</div>
</nav>
);
};
export default Navbar;
The problem is that the display property (via the hidden class) cannot be animated, you can see the whole list of animatable properties here.
You can animate height, but it requires specifying the full menu height explicitly (auto will not animate), so h-32 in the code below is just an example, you may need to change it depending on your exact circumstances.
Here's an example:
<div
className={`${
active ? 'h-32' : 'h-0'
} transition-all delay-150 duration-300 overflow-hidden w-full`}
>
...
Note that transition-all is used, simple transition will not animate height, and ease-in-out is removed, as it is redundant, the same timing function is already included in transition-all.
Related
Initially I made a project and there the Navbar was completely ok. But I want to use the same Navbar on similar kind of project. But while type or copy paste the code the design is completely change. Even after a lot of search I can't find the actual problem as well as the solution also.
Both having same CSS file as well. Then where the problem occurs ?? Is there any change happened for Tailwind CSS design ?? Kindly let me know.
Navbar of previous project :
Navbar of present project :
Even though all codes are same. I put all the Navbar code below.
import { HiMenuAlt4 } from 'react-icons/hi';
import { AiOutlineClose } from 'react-icons/ai';
import logo from '../../images/logo.png';
const NavbarItem = ({ title, classProps }) => {
return (
<li className={`mx-4 cursor-pointer ${classProps}`}>
{title}
</li>
)
}
const Navbar = () => {
const [toggleMenu, setToggleMenu] = useState(false); //Mobile View On or Not
return (
<nav className="w-full flex md:justify-center justify-between items-center p-4">
<div className="md:flex-[0.5] flex-initial justify-center items-center">
<img src={logo} alt="logo" className="w-32 cursor-pointer"/>
</div>
<ul className="text-white md:flex hidden list-none flex-row justify-between items-center flex-initial">
{["Buy","Sell","Transfer","Wallets","About Us"].map((item, index) => (
<NavbarItem key={item + index} title={item} />
))}
<li className="bg-[#3d4f79] py-2 px-7 mx-4 rounded-full cursor-pointer hover:bg-[#2546]">
SIGN IN
</li>
</ul>
{/* Mobile View */}
<div className="flex relative">
{toggleMenu
? <AiOutlineClose fontSize={28} className="text-white md:hidden cursor-pointer" onClick={() => setToggleMenu(false)} />
: <HiMenuAlt4 fontSize={28} className="text-white md:hidden cursor-pointer" onClick={() => setToggleMenu(true)} />
}
{toggleMenu && (
<ul
className="z-10 fixed top-0 -right-2 p-3 w-[70vw] h-screen shadow-2x1 md:hidden list-none
flex flex-col justify-start items-end rounded-md blue-glassmorphism text-white animate-slide-in"
>
<li className="text-xl w-full my-2">
<AiOutlineClose onClick={() => setToggleMenu(false)} />
</li>
{["Market","Exchange","Tutorials","Wallets"].map((item, index) => (
<NavbarItem key={item + index} title={item} classProps="my-2 text-lg"/>
))}
</ul>
)}
</div>
</nav>
);
}
export default Navbar;```
by adding classname navbar fixed <nav className="fixed w-full flex md:justify-center justify-between items-center p-4">
I'm trying to implement google authentication on my nextjs app. i'm implementing this in my layout component,
when i use user = null and isLoadingUser the button is loading fine but when changed to user = session?.user and isloadingUser = 'loading' the button is set being set to disabled?
Layout coponent code:
import { Fragment, useState } from 'react';
import { useRouter } from 'next/router';
import Head from 'next/head';
import Link from 'next/link';
import Image from 'next/image';
import PropTypes from 'prop-types';
import AuthModal from './AuthModal';
import { Menu, Transition } from '#headlessui/react';
import {
HeartIcon,
HomeIcon,
LogoutIcon,
PlusIcon,
SparklesIcon,
UserIcon,
} from '#heroicons/react/outline';
import { ChevronDownIcon } from '#heroicons/react/solid';
import { useSession, signOut } from 'next-auth/react';
const menuItems = [
{
label: 'List a new home',
icon: PlusIcon,
href: '/list',
},
{
label: 'My homes',
icon: HomeIcon,
href: '/homes',
},
{
label: 'Favorites',
icon: HeartIcon,
href: '/favorites',
},
{
label: 'Logout',
icon: LogoutIcon,
onClick: signOut,
},
];
const Layout = ({ children = null }) => {
const router = useRouter();
const { data: session, status } = useSession()
const [showModal, setShowModal] = useState(false);
const user = session?.user
const isLoadingUser = 'loading';
const openModal = () => setShowModal(true);
const closeModal = () => setShowModal(false);
return (
<>
<Head>
<title>SupaVacation | The Modern Dev</title>
<meta
name="title"
content="Learn how to Build a Fullstack App with Next.js, PlanetScale & Prisma | The Modern Dev"
/>
<link rel="icon" href="/favicon.ico" />
</Head>
<div className="min-h-screen flex flex-col">
<header className="h-16 w-full shadow-md">
<div className="h-full container mx-auto">
<div className="h-full px-4 flex justify-between items-center space-x-4">
<Link href="/">
<a className="flex items-center space-x-1">
<SparklesIcon className="shrink-0 w-8 h-8 text-rose-500" />
<span className="text-xl font-semibold tracking-wide">
Supa<span className="text-rose-600">Vacation</span>
</span>
</a>
</Link>
<div className="flex items-center space-x-4">
<Link href="/create">
<a className="hidden sm:block hover:bg-gray-200 transition px-3 py-1 rounded-md">
List your home
</a>
</Link>
{isLoadingUser ? (
<div className="h-8 w-[75px] bg-gray-200 animate-pulse rounded-md" />
) : user ? (
<Menu as="div" className="relative z-50">
<Menu.Button className="flex items-center space-x-px group">
<div className="shrink-0 flex items-center justify-center rounded-full overflow-hidden relative bg-gray-200 w-9 h-9">
{user?.image ? (
<Image
src={user?.image}
alt={user?.name || 'Avatar'}
layout="fill"
/>
) : (
<UserIcon className="text-gray-400 w-6 h-6" />
)}
</div>
<ChevronDownIcon className="w-5 h-5 shrink-0 text-gray-500 group-hover:text-current" />
</Menu.Button>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Menu.Items className="absolute right-0 w-72 overflow-hidden mt-1 divide-y divide-gray-100 origin-top-right bg-white rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
<div className="flex items-center space-x-2 py-4 px-4 mb-2">
<div className="shrink-0 flex items-center justify-center rounded-full overflow-hidden relative bg-gray-200 w-9 h-9">
{user?.image ? (
<Image
src={user?.image}
alt={user?.name || 'Avatar'}
layout="fill"
/>
) : (
<UserIcon className="text-gray-400 w-6 h-6" />
)}
</div>
<div className="flex flex-col truncate">
<span>{user?.name}</span>
<span className="text-sm text-gray-500">
{user?.email}
</span>
</div>
</div>
<div className="py-2">
{menuItems.map(
({ label, href, onClick, icon: Icon }) => (
<div
key={label}
className="px-2 last:border-t last:pt-2 last:mt-2"
>
<Menu.Item>
{href ? (
<Link href={href}>
<a className="flex items-center space-x-2 py-2 px-4 rounded-md hover:bg-gray-100">
<Icon className="w-5 h-5 shrink-0 text-gray-500" />
<span>{label}</span>
</a>
</Link>
) : (
<button
className="w-full flex items-center space-x-2 py-2 px-4 rounded-md hover:bg-gray-100"
onClick={onClick}
>
<Icon className="w-5 h-5 shrink-0 text-gray-500" />
<span>{label}</span>
</button>
)}
</Menu.Item>
</div>
)
)}
</div>
</Menu.Items>
</Transition>
</Menu>
) : (
<button
type="button"
onClick={openModal}
className="ml-4 px-4 py-1 rounded-md bg-rose-600 hover:bg-rose-500 focus:outline-none focus:ring-4 focus:ring-rose-500 focus:ring-opacity-50 text-white transition"
>
Log in
</button>
)}
</div>
</div>
</div>
</header>
<main className="flex-grow container mx-auto">
<div className="px-4 py-12">
{typeof children === 'function' ? children(openModal) : children}
</div>
</main>
<AuthModal show={showModal} onClose={closeModal} />
</div>
</>
);
};
Layout.propTypes = {
children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
};
export default Layout;
I'm currently building a next.js app and I've run into an issue with Firebase (v8) Authentication where eventhough I can login, (and it works) I can't access the logged in user in my header since the the property of the user image is apparently undefinedeventhough on the console it appears!
import Image from "next/image";
import { MenuIcon, UserCircleIcon, SearchIcon, UsersIcon } from '#heroicons/react/solid';
import { useState } from "react"
import 'react-date-range/dist/styles.css'; // main style file
import 'react-date-range/dist/theme/default.css'; // theme css file
import { DateRange } from 'react-date-range';
import { useRouter } from "next/router";
import firebase from "../firebase/clientApp";
import { useAuthState } from 'react-firebase-hooks/auth'
function Header({ placeholder }) {
const [searchInput, setSearchInput] = useState("");
const [startDate, setStartDate] = useState(new Date());
const [endDate, setEndDate] = useState(new Date());
const [noOfGuests, setNoOfGuests] = useState(1);
const router = useRouter();
return(
<header className='sticky top-0 z-50 grid grid-cols-3 bg-white shadow-md p-5 md:px-10'>
{/* left */}
<div className='relative flex items-center h-10 cursor-pointer my-auto'>
</div>
{/* middle - search */}
<div className='flex items-center mb:border-2 rounded-full py-2 md:shadow-sm'>
<input
value = {searchInput}
className='flex-grow pl-5 bg-transparent outline-none text-sm text-gray-600 placeholder-gray-400'
type="text"
/>
<SearchIcon
className='hidden md:inline-flex h-8 bg-blue-800 text-white rounded-full p-2 cursor-pointer md:mx-2'
/>
</div>
{/* right */}
<div className='flex items-center space-x-4 justify-end text-gray-500'>
<p className='hidden md:inline cursor-pointer'>Become a host</p>
<div className='flex items-center space-x-2 border-2 p-2 rounded-full cursor-pointer'>
<div className="flex items-center space-x-2" onClick={() => router.push("/login")}>
<MenuIcon className='h-6'/>
{/* Icon change - Here is where the code kabooms */}
{firebase.auth().currentUser !== null ?
(<Image className="h-6" src={firebase.auth().photoURL} width="100%" height="100%" objectFit="cover"/>):(<UserCircleIcon className='h-6'/>)}
</div>
</div>
</div>
</header>
);
}
export default Header
You would find photoURL property inside currentUser.
Change <Image className="h-6" src={firebase.auth().photoURL} width="100%" height="100%" objectFit="cover"/> to (<Image className="h-6" src={firebase.auth().currentUser.photoURL} width="100%" height="100%" objectFit="cover"/>
So I'm making this app and I need to fade in the menu when I click the button. I have it rendering on click using state, but I can't get it to fade in / fade out on click. When I edit the opacity value inside Chrome Dev Console the transition works fine, but when I want to change it using state it doesn't.
Any help? Thanks in advance!
import React, { useState } from "react";
import { useRouter } from "next/router";
import { MenuIcon, XIcon } from "#heroicons/react/outline";
function Header() {
const router = useRouter();
const [popCard, setPopCard] = useState("hidden");
const [fade, setFade] = useState(true);
const handleMenuClick = () => {
setPopCard("inline-block");
setFade(true);
};
const handleXClick = () => {
setPopCard("hidden");
setFade(false);
};
return (
<div className="text-center">
<header className="sticky z-50 top-0 shadow-md bg-white border-b p-5">
<div className="flex justify-between items-center">
<h1
className="text-6xl text-red-500 cursor-pointer"
onClick={() => router.push("/")}
>
Velvet
</h1>
<MenuIcon
className="h-8 text-red-500 cursor-pointer"
onClick={handleMenuClick}
/>
</div>
</header>
<div
className={
popCard +
" w-[60%] flex-col border my-10 pb-3 rounded-3xl shadow-lg transition duration-300 ease-in-out " +
`${fade === true ? "opacity-100" : "opacity-0"}`
}
>
<div className="flex justify-end">
<XIcon
className="h-6 text-red-500 cursor-pointer mt-2 mr-2 opacity-70"
onClick={handleXClick}
/>
</div>
<div className="space-y-8 text-3xl text-center mt-5 mb-10 text-red-500">
<h1>Contac</h1>
<h1>About Us</h1>
</div>
</div>
</div>
);
}
export default Header;
codesandbox: Sandbox
Just to be clear, I want the menu card to fade in when I click the menu button, and I want the menu card to fade out when I click the close button.
The solution is, you need to add duration, like this:
`transition-all duration-200 ${fade ? "opacity-100" : "opacity-0"}`
Here is my forked sandbox you had given, I've removed extra inline CSS, so it may become evident.
Here is the complete code:
function Header() {
const [popCard, setPopCard] = useState("hidden");
const [fade, setFade] = useState(false);
const handleMenuClick = () => {
setPopCard("inline-block");
setFade(true);
};
const handleXClick = () => {
setPopCard("hidden");
setFade(false);
};
console.log(fade, "fade");
return (
<div className="text-center">
<header className="sticky z-50 top-0 shadow-md bg-white border-b p-5">
<div className="flex justify-between items-center">
<h1 className="text-6xl text-red-500 cursor-pointer">Velvet</h1>
<button
className="text-3xl border rounded-lg px-5"
onClick={handleMenuClick}
>
Menu
</button>
</div>
</header>
<div className="p-10">
<div
className={`transition-all duration-200 ${
fade ? "opacity-100" : "opacity-0"
}`}
>
<div className="flex justify-end">
<button className="mt-2 mr-2 border p-2" onClick={handleXClick}>
Close
</button>
</div>
<div className="space-y-2 text-3xl text-center mt-5 mb-10 mx-5 text-red-500">
<h1>Kontakt</h1>
<h1>O Velvetu</h1>
</div>
</div>
</div>
</div>
);
}
export default Header;
Sandbox: https://codesandbox.io/s/sweet-swartz-mr3nru?file=/pages/index.js:41-1396
I am new to Ract and building a multi step form in Next.js, where I also use Context. So my project structure is pretty wild and I don't get how / where to change the steps.status when moving to next step in the stepper. So far I have my context, managing half of states, basically the formData, but also the 'original' state of my stepper:
import { useState, createContext, useContext } from "react";
export const FormContext = createContext();
export default function FormProvider({ children }) {
const [data, setData] = useState({});
const [steps, setSteps] = useState([
{ name: 'Vertrag', status: 'current' },
{ name: 'Dateneingabe', status: 'upcoming' },
{ name: 'Bestätigung', status: 'upcoming' },
]);
const setFormValues = (values) => {
setData((prevValues) => ({
...prevValues,
...values,
}));
};
return (
<FormContext.Provider value={{ steps, data, setFormValues }}>
{children}
</FormContext.Provider>
);
}
export const useFormData = () => useContext(FormContext);
In Stepper.js I therefore import my formData:
import { CheckIcon } from '#heroicons/react/solid'
import { useContext } from 'react'
import { FormContext } from "../context";
// status: 'complete', 'current', 'upcoming'
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
export default function Stepper() {
const formData = useContext(FormContext);
const steps = formData.steps
return (
<nav aria-label="Progress">
<div className="flex items-center flex-col">
<ol className="flex items-center sm:flex-col md:flex-row mx-auto mt-32 mb-8">
{steps.map((step, stepIdx) => (
<li key={step.name} className={classNames(stepIdx !== steps.length - 1 ? 'pr-16 sm:pr-32' : '', 'relative')}>
{step.status === 'complete' ? (
<>
<div className="absolute inset-0 flex items-center" aria-hidden="true">
<div className="h-0.5 w-full bg-yellow-500" />
</div>
<a
href="#"
className="relative w-8 h-8 flex items-center justify-center bg-yellow-500 rounded-full hover:bg-yellow-500"
>
<span className="h-9 flex flex-col items-center">
<span className="relative top-2 z-10 w-8 h-8 flex items-center justify-center rounded-full group-hover:bg-indigo-800">
<CheckIcon className="w-5 h-5 text-white" aria-hidden="true" />
</span>
<span className="text-xs font-semibold tracking-wide text-gray-600 mt-8">{step.name}</span>
</span>
</a>
</>
) : step.status === 'current' ? (
<>
<div className="absolute inset-0 flex items-center" aria-hidden="true">
<div className="h-0.5 w-full bg-gray-200" />
</div>
<a
href="#"
className="relative w-8 h-8 flex items-center justify-center bg-white border-2 border-yellow-500 rounded-full"
aria-current="step"
>
<span className="h-9 flex flex-col items-center">
<span className="z-10 w-8 h-8 flex items-center justify-center rounded-full group-hover:bg-indigo-800">
<span className="relative h-2.5 w-2.5 bg-yellow-500 rounded-full relative" style={{top: '0.8rem'}} />
</span>
<span className="text-xs font-semibold tracking-wide text-gray-600" style={{marginTop: '2.72rem'}}>{step.name}</span>
</span>
</a>
</>
) : (
<>
<div className="absolute inset-0 flex items-center" aria-hidden="true">
<div className="h-0.5 w-full bg-gray-200" />
</div>
<a
href="#"
className="group relative w-8 h-8 flex items-center justify-center bg-white border-2 border-gray-300 rounded-full hover:border-gray-400"
>
<span className="h-9 flex flex-col items-center">
<span className="z-10 w-8 h-8 flex items-center justify-center rounded-full">
<span className="relative h-2.5 w-2.5 bg-transparent rounded-full group-hover:bg-gray-300" style={{top: '0.8rem'}} />
</span>
<span className="text-xs font-semibold tracking-wide text-gray-600" style={{marginTop: '2.72rem'}}>{step.name}</span>
</span>
</a>
</>
)}
</li>
))}
</ol>
</div>
</nav>
)
Moreover I have index.js page, where all the components come together
import { useState } from "react";
import Head from "next/head";
import Stepper from '../components/Stepper'
import styles from "../styles/styles.module.scss";
import FormCard from "../components/FormCard";
import Navbar from "../components/Navbar";
import { CheckIcon } from '#heroicons/react/solid'
import {
PersonalInfo,
ConfirmPurchase,
ContractInfo,
} from "../components/Forms";
import FormCompleted from "../components/FormCompleted";
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
const App = () => {
const [formStep, setFormStep] = useState(0);
const nextFormStep = () => setFormStep((currentStep) => currentStep + 1);
const prevFormStep = () => setFormStep((currentStep) => currentStep - 1);
const [activeStep, setActiveStep] = useState(0);
const handleNextStep = () => {
setActiveStep((prevActiveStep) => prevActiveStep + 1);
};
const handlePrevoiusStep = () => {
setActiveStep((prevActiveStep) => prevActiveStep - 1);
};
return (
<div>
<Head>
<title>Next.js Multi Step Form</title>
</Head>
< Navbar />
< Stepper activeStep={activeStep} />
<div className={styles.container}>
<FormCard currentStep={formStep} prevFormStep={prevFormStep}>
{formStep >= 0 && (
<ContractInfo formStep={formStep} nextFormStep={nextFormStep} />
)}
{formStep >= 1 && (
<PersonalInfo formStep={formStep} nextFormStep={nextFormStep} />
)}
{formStep >= 2 && (
<ConfirmPurchase formStep={formStep} nextFormStep={nextFormStep} />
)}
{formStep > 2 && <FormCompleted />}
</FormCard>
</div>
<div className="mt-1 mb-5 sm:mt-8 sm:flex sm:justify-center lg:justify-center">
<div className="rounded-md shadow">
<a role="button" tabIndex={0}
onClick={ () => { prevFormStep(); handlePrevoiusStep() }}
className="w-full flex items-center justify-center px-8 py-3 border border-transparent text-base font-medium rounded-md text-white bg-yellow-500 hover:bg-yallow-600 md:py-4 md:text-lg md:px-10"
>
Back
</a>
</div>
<div className="mt-3 sm:mt-0 sm:ml-3">
<a
onClick={ () => { nextFormStep(); handleNextStep() }}
className="w-full flex items-center justify-center px-8 py-3 border border-transparent text-base font-medium rounded-md text-white bg-yellow-500 hover:bg-yallow-600 md:py-4 md:text-lg md:px-10"
>
Next
</a>
</div>
</div>
</div>
);
};
export default App;
As you see, Stepper is managed in three different files. But I am at least capable to change the activeStep index when clicking on Buttons, which already was a huge challenge for me. So now I also need the design to change. So that activeStep gets the step.status === 'current'. All stepps index < activeStep index should get step.status === 'complete' and logically all stepps index > activeStep index - step.status === 'upcoming'. Now I tried to handle this in index.js, but of course get back step is undefined, even though it is defined in Stepper.js through context.