TailwindCSS animations on conditionally rendered components in React - javascript

If I am conditionally rendering a component depending on some state, how can I animate its transition between its open and closed states in React with TailwindCSS?
{successMessage && (
<div className="flex transition-all ease-in-out duration-300 bg-gray-200 w-44 items-center justify-between px-2 rounded">
<p>Added to watchlist!</p>
<button onClick={() => setSuccessMessage(false)}>X</button>
</div>
)}
This code half works but there is no animation or transition period to it. How can I fix this?

Try something like this :
<div className={`flex transition-all ease-in-out duration-300 bg-gray-200 w-44 items-center justify-between px-2 rounded ${your_state ? 'opacity-100' : 'opacity-0'}`}>
...
</div>

The "official" solution is to use Headless UI's Transition component.
Headless UI is created and maintained by the same authors of Tailwind CSS.

Two states works great.
With first one add/remove "hidden" class.
And with second one change opacity/height/translate or what you need for animation.
Use useEffect and setTimeout with 0 delay for changing the state of secondState. like below:
useEffect(() => {
setTimeout(() => {
setSecondState(firstState)
}, 0) }, [firstState])
<div className={`${firstState ? "hidden" : ""} ${secondState ? "opacity-100" : "opacity-0"}`} />

I would recommend AOS libary to do this, as you would need to do some more work to make this work with TailwindCSS.
Try this
Install Aos
npm install aos --save
Put in your file
import React, { useEffect } from "react";
import AOS from 'aos';
import "aos/dist/aos.css";
useEffect(() => {
AOS.init({
duration : 1000
});
}, []);
You can change duration as you like.
Add as attribute to HTML tag
data-aos="animation_name"
Example
<div> data-aos="fadeIn" </div>
Extra Attributes you can use
data-aos="fade-up"
data-aos-offset="200"
data-aos-delay="50"
data-aos-duration="1000"
data-aos-easing="ease-in-out"
data-aos-mirror="true"
data-aos-once="false"
data-aos-anchor-placement="top-center"
List of all animation
Documentation

Related

NextJs nesting a component into another (not FC)

I built a module, then broke it up into components and trying to put it back together.
The components work. Some components go inside the div of another component.
I have tried putting them into a div scaffold, but i was then writing more css to bring the module together.
I thought we just do this:
<CompOne>
<CompTwo />
</CompOne>
This gives an error:
Type '{ children: Element; }' has no properties in common with type 'IntrinsicAttributes'.
So maybe the above is write i need to typescript? sorry couldnt find a working example on this.
function WaldoEye() {
return (
<WaldoEyeball>
<WaldoRetina/>
</WaldoEyeball>
)
}
export default WaldoEye
function WaldoEyeball() {
return (
<div className="
flex
relative
items-center
opacity-90
w-40 h-40
rounded-full
shadow-[inset_0_-15px_15px_-3px_rgba(5,10,255,0.3)]
bg-gradient-to-r
from-slate-50
via-slate-100
to-slate-50
">
<div className="
absolute
flex
items-center
opacity-90
w-40 h-40
rounded-full
shadow-[0_60px_55px_-25px_rgba(255,255,255,0.4)]
">
</div>
</div>
)
}
export default WaldoEyeball
function WaldoRetina() {
return (
<>
<div className="
flex
items-center
relative
mx-auto
w-16
h-16
rounded-full
border-2
border-sky-500
bg-gradient-radial
from-cyan-500
via-sky-300
to-sky-500
">
</div>
</>
)
}
export default WaldoRetina
So maybe the above is write i need to typescript? sorry couldnt find a working example on this.
Currently the WaldoEyeball component doesn't expect any children. You will need to adjust the props in the WaldoEyeball component so it accepts children.
const WaldoEyeball: FC = ({ children }) => {
return (
<div className="
flex
relative
items-center
opacity-90
w-40 h-40
rounded-full
shadow-[inset_0_-15px_15px_-3px_rgba(5,10,255,0.3)]
bg-gradient-to-r
from-slate-50
via-slate-100
to-slate-50
">
<div className="
absolute
flex
items-center
opacity-90
w-40 h-40
rounded-full
shadow-[0_60px_55px_-25px_rgba(255,255,255,0.4)]
">
{children} // drop children somewhere to render it
</div>
</div>
);
}

TailwindCSS scale class works inconsistently while being used with React state

I'm using react and tailwindcss to create a web app for news. Headline of the page looks like the picture below (the image and text were randomly chosen):
When I hover my mouse on the div the image is supposed to zoom in while changing the state on hover and setting the scale while based on the isMouseIn boolean value. But the problem is that it sometimes works but other times it doesn't. I tried checking the state value and it works perfectly, the values are getting set without any problems but it doesn't scale when I enter the page for the first time. If I refresh the page or change the scale while manually in the code, then it works but otherwise it doesn't. Is this maybe a bug from react or am I doing something wrong?
Check the code down below for a better understanding of my implementation:
export default function Headline() {
/*
*
* green border --> the whole component
* orange border --> div that is darkening the whole component
*/
const [isMouseIn, setMousePos] = useState(false);
function mouseEnter() {
setMousePos(true);
}
function mouseLeave() {
setMousePos(false);
}
return (
<div
onMouseEnter={() => mouseEnter()}
onMouseLeave={() => mouseLeave()}
className="mb-[.1em] overflow-hidden 950:rounded-xl cursor-pointer w-[100%] h-[300px] 380:h-[400px] 1215:h-[500px] max-h-[500px] relative shadow-2xl"
>
<img
src={headline}
className={`w-full scale-${
isMouseIn ? "150" : "100"
} object-cover transition-all duration-700 h-full max-h-full absolute`}
/>
.
.
.
.
.
We can use group modifier of tailwindcss.
Give "group" class the parent element
Give class names to child element according to the parent elements state
export default function Headline() {
return <div
className="
group mb-[.1em] overflow-hidden 950:rounded-xl cursor-pointer w-[100%]
h-[300px] 380:h-[400px] 1215:h-[500px] max-h-[500px] relative shadow-2xl"
>
<img
src={"https://i.stack.imgur.com/6TEEa.png"}
className="
object-cover transition-all duration-700 h-full max-h-full absolute
group-hover:scale-150 scale-100"
/>
</div>;
};
Referance
Tailwind CSS Doc: Group Modifier

Applying Tailwind overflow behavior to only one child element

I'm using Tailwind to style a React component called "BlurImage" which displays an image by default and then on hover removes the image and displays a button at the bottom of the component and a text box at the top that has overflow-y-auto behavior to allow for scrolling if the text grows too long.
By default, the overflow responsibility is given to the body as discussed here and so I need to give the parent top-level div of BlurImage overflow as well. This causes both the text and the button to be scrollable. Is there a way to avoid having the button scroll?
This seems like it should be a common situation - I can imagine using this concept to write self-contained components that have a header/footer and some scrollable content as well. Unfortunately, I can't find much addressing this in the Tailwind docs or online.
I appreciate any suggestions! Here is the component code that I currently have:
import Image from 'next/image';
import cn from 'classnames';
import { useState } from 'react';
import { ImageInfo } from '../../types/images';
import Button from './button';
import { useRouter } from 'next/router';
type BlurImageProps = {
image: ImageInfo;
};
const BlurImage = ({ image }: BlurImageProps): JSX.Element => {
const [isLoading, setLoading] = useState(true);
return (
<div className="group shrink-0 h-40 w-40 relative aspect-w-1 aspect-h-1 overflow-hidden rounded-lg xl:aspect-w-7 xl:aspect-h-8 drop-shadow-xl bg-black">
<Image
alt=""
src={image.url}
width={512}
height={512}
className={cn(
'flex h-full duration-700 ease-in-out group-hover:opacity-20',
{
'scale-110 blur-2xl grayscale': isLoading,
'scale-100 blur-0 grayscale-0': !isLoading,
},
)}
onLoadingComplete={() => setLoading(false)}
/>
{!isLoading && (
<div className="absolute bottom-0 left-0 overflow-y-scroll items-center justify-center w-full h-full align-middle text-center px-2 opacity-0 duration-700 ease-in-out group-hover:opacity-100">
<a href={image.url}>
<p className="text-base text-white mb-2">
{image.prompt}
</p>
</a>
<Button
className="flex-shrink-0 px-2 py-2 text-sm font-bold text-white rounded bg-green-500"
type="button"
text="click me"
isSubmit={true}
onClick={() => console.log("clicked")}
/>
</div>
)}
</div>
);
};
export default BlurImage;

How can I setState of an Image component with useState hook when the html DOMelement's classlist contains the string "dark"?

I'm new to React and I wish building a portfolio website.
I need an image to be changed when a button is being toggled to lightMode (this button is in another component called Switcher).
I'm using tailwind so when the button is toggled the html DOMelement's classlist is set to "dark", and reset to ""(empty string) when toggling back...
Inside a a component called "Home" the image should switch every time the button is clicked.
So to get it switching I'm testing if classlist of html DOMelement contains "dark" like so:
Home.js
import React, {useEffect, useRef, useState} from 'react';
import {AiFillGithub} from "react-icons/ai";
import {SiFacebook, SiCodepen, SiLinkedin} from "react-icons/si";
import darkImg from "../images/bg.jpg";
import lightImg from "../images/bg-light.jpg";
function Home(props) {
const html = document.querySelector("html");
const [imgg, setImgg] = useState(<img className="ml-14" src={darkImg} alt="home"/>);
useEffect(() => {
if (html.classList.contains("dark")){
setImgg(<img className="ml-14" src={lightImg} alt="home"/>);
}
else {
setImgg(<img className="ml-14" src={darkImg} alt="home"/>);
}
})
return (
<div className="h-full mt-[2px] flex-row">
<Img path={imgg}/>
<div className="font-arvo tracking-wider text-center text-7xl">PORTFOLIO</div>
<div className="text-center text-4xl">Software Engineer</div>
<div className="flex flex-row items-center justify-center mt-5 space-x-7">
<AiFillGithub className="social-icons" size="30"/>
<SiFacebook className="social-icons" size="30"/>
<SiCodepen className="social-icons" size="30"/>
<SiLinkedin className="social-icons" size="30"/>
</div>
</div>
);
}
const Img = (props) => {
return props.path;
}
export default Home;
Switcher.js
import React, {useEffect, useRef, useState} from 'react';
import {HiLightBulb} from "react-icons/hi";
import {MdDarkMode} from "react-icons/md";
function Switcher(props) {
const [foo, setFoo] = useState(
{
decor: "flex flex-row w-6 h-6 md:w-7 md:h-7 relative rounded-full transition duration-500 transform bg-two -translate-x-2 pt-1 pl-0.5 text-black",
icon: <MdDarkMode size="20"/>
}
);
const [isDark, setIsDark] = useState(true);
let Style1 = "flex flex-row w-6 h-6 md:w-7 md:h-7 relative rounded-full transition duration-500 transform bg-two -translate-x-2 pt-1 pl-0.5 text-black dark:bg-nine dark:text-seven";
let Style2 = "flex flex-row w-6 h-6 md:w-7 md:h-7 relative rounded-full transition duration-500 transform bg-two translate-x-full pt-1 pl-0.5 text-black dark:bg-nine dark:text-seven";
let icon1 = <MdDarkMode size="20"/>;
let icon2 = <HiLightBulb size="20"/>;
const html = document.querySelector("html");
function switchTheme() {
setIsDark(!isDark);
if(!isDark){
html.classList.add("dark");
setFoo({decor: Style2, icon: icon2});
}else{
html.classList.remove("dark");
setFoo({decor: Style1, icon: icon1});
}
}
return (
<Toggler decor={foo.decor} icon={foo.icon} onToggle={switchTheme}/>
);
}
const Toggler = (props) => {
return (
<button onClick={props.onToggle} className="absolute top-9 right-10 w-14 h-5 rounded-2xl flex items-center transition duration-300 focus:outline-none shadow bg-four dark:bg-white">
<div id="switch-toggle" className={props.decor}>
{props.icon}
</div>
</button>
);
};
export default Switcher;
On the browser's console I got this warning saying :
Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
at Home (http://localhost:3000/main.428ce48dfed5fa0fec8a.hot-update.js:38:74)
at div
at App
I can see the image switching on Toggle but i don't think it's a clean use of hooks in Home.js
Can Somebody provide any ideas... Thanks.

Issue with Changing state from 1 React Component inside of another React component

I've been trying to change the 'ModalOn' state which is created inside of the medCardSong.js file, and I've been trying to change that state from inside of the 'SongModal.js' file, which is a child component inside of medCardSong.js.
I've inputted the changeState function 'SetModalOn' as a prop to the SongModal.js component, and i've tried changing the state through that.
Here's medCardSong.js:
import React, { useEffect } from 'react';
import { useState} from 'react';
import SongModal from '../modals/SongModal';
function MediumCardSong(props) {
const [ModalOn, SetModalOn] = useState(false);
function killme() {
SetModalOn(false);
console.log(7)
}
console.log(ModalOn)
return (
<div className={" flex flex-col m-2 overflow-hidden duration-300 w-52 " + (ModalOn
? 'transition-none' : 'hover:scale-105 transition-all')} onClick={() =>
{SetModalOn(true);}}>
<img className='object-cover rounded-3xl'
src="https://i0.wp.com/coolhunting.com/wp-content/uploads/2022/07/steve-lacy-
bad-habit.jpg?fit=586%2C586&ssl=1" alt="" />
<div className='pb-2'>
<div className='flex'>
<div className='px-2 pt-2 text-2xl font-bold text-gray-400'>#1</div>
<div className='pl-3 text-xl pt-2 text-white'>Mercury</div>
</div>
<div className='text-left pl-5 text-gray-500'>Steve Lacy</div>
</div>
{ModalOn && <SongModal CloseModal={killme} />}
</div>
);
}
export default MediumCardSong;
and here's SongModal.js:
import React from 'react'
function SongModal(props) {
// setTimeout(() => {props.CloseModal(false)}, 1000)
return (
<div className="bg-neutral-800 bg-opacity-60 fixed inset-0 z-50 backdrop-blur-sm">
<div className="flex h-screen justify-center items-center">
<div className="justify-center bg-neutral-700 py-12 px-24 border-4 border-
pearmint rounded-xl text-xl text-white" >
<button className='text-3xl text-white pr-24 pb-24'
onClick={() => {props.CloseModal()}} >X</button>
sad
</div>
</div>
</div>
)
};
export default SongModal;
The imported CloseModal function works as intended when it's applied outside of the jsx. For example, the "SetTimeOut" piece of code would work properly if it's uncommmented. However this doesn't happen when I call "CloseModal" inside of an Onclick event-handler, such as the call I did for the 'x' Button.
I've also used console.log to see if the button has been registering the clicks I make and it has been. So I'm confused as to why the props.CloseModal function does not work as intended inside the OnClick event listener. Please give advice if you can.
try to call it inside of a hook
function SongModal(props) {
const close = () => {
props.CloseModal()
}
return (
<div>
<button onClick={close}>Close Btn</button>
</div>
)
};
also check the following acritical
link

Categories

Resources