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
Related
I have a following set of images each with its own div and I want to show a popup with information on hover. Refer the following component code-
function Skill({ directionLeft, skill }: Props) {
return (
//group hover filter class in motion img used for special effect
<div className='group relative flex cursor-pointer'>
<motion.div
initial={{
x: directionLeft ? -200 : 200,
opacity: 0
}}
transition={{ duration: 0 }}
whileInView={{ opacity: 1, x: 0 }}
className='w-16 h-16 rounded-full border border-gray-500 object-cover xl:w-20 xl:h-20 filter group-hover:grayscale transition duration-300 ease-in-out'
>
<Image
src={urlFor(skill.skillImage).url()}
height={108} width={192} alt='' className=' w-16 h-16 rounded-full border border-gray-500 object-cover xl:w-20 xl:h-20 filter group-hover:grayscale transition duration-300 ease-in-out' />
</motion.div>
<div className='absolute opacity-0 group-hover:opacity-90 transition duration-300 ease-in-out z-20 group-hover:bg-[#1e313f] h-54 xl:w-72 rounded-lg p-5'>
<div className='flex flex-col items-center justify-center h-full'>
{/*loop over if multiple skill supports*/}
{skill.relevantWorkDone.map((relevantWorkDone, index) => (
<p key={index} className='uppercase tracking-[5px] text-gray-200 text-sm overflow-y-auto opacity-100 z-20= justify-center'>
-{relevantWorkDone}
</p>
))}
</div>
</div>
</div>
)
}
Now I want to adjust the hovering of the popup messages according to the location of the parent div in super parent grid.
Eg- instead of 1
I want something like 2-
The image div being hovered on is the one in the one in the last column if the 2nd last row.
I know I can pass a prop with the grid location like I and create a function depending upon the remainder to make it flow either left or right and if I is in the first half or second half of total elements to make it flow from either top or bottom.
But I don't know what tailwind CSS classes to use to achieve this.
Any help would be appreciated.
I have a div with three children, and a button that when pushed changes their relative position to slide over into frame. As a view slides over into frame, the other views should not only slide out, but also become hidden (to not take up vertical space).
Currently, I'm using the 'visibility' css property to show/hide the div after transition, but that doesn't collapse the height of the parent container as the hidden div still takes up vertical space.
Code Using 'Visibility' Property
useEffect(() => {
updating position css attribute via style dict...
switch(activePage) {
case 1:
setPageOneVisible(true)
setTimeout(setPageTwoVisible(false), 500)
break
case 2:
setPageTwoVisible(true)
setTimeout(setPageOneVisible(false), 500)
setTimeout(setPageThreeVisible(false), 500)
break
case 3:
setPageThreeVisible(true)
setTimeout(setPageTwoVisible(false), 500)
}
}, [activePage])
Using the 'display: none' or 'height: 0' properties works in the sense that the parent container collapses, but for some reason, even if applying these properties using the setTimeOut() function to only trigger after the transition is completed, the divs get hidden instantaneously and don't wait for the timer.
Code Using 'Display' Property
useEffect(() => {
setPageOnePosDict(prevState => ({
...prevState,
['display']: pageOneVisible ? 'block' : 'none'
}))
setPageTwoPosDict(prevState => ({
...prevState,
['display']: pageTwoVisible ? 'block' : 'none'
}))
setPageThreePosDict(prevState => ({
...prevState,
['display']: pageThreeVisible ? 'block' : 'none'
}))
}, [pageOneVisible, pageTwoVisible, pageThreeVisible])
Why does react appear to ignore the useTimeOut function when the 'display' style is being added?
The JSX code for the 3 divs is:
<div id='screen1' className='relative w-full bg-blue-100 h-min overlap transition-all duration-500' style={pageOnePosDict}>
<div className='w-full h-[400px] bg-transparent text-center'>
<div className='pt-[200px]'>1</div>
</div>
</div>
<div id='screen2' className='relative w-full bg-green-100 h-min overlap transition-all duration-500' style={pageTwoPosDict}>
<div className='w-full h-[200px] bg-transparent text-center'>
<div className='pt-[100px]'>2</div>
</div>
</div>
<div id='screen3' className='relative w-full bg-purple-100 h-min overlap transition-all duration-500' style={pageThreePosDict}>
<div className='w-full h-[100px] bg-transparent text-center'>
<div className='pt-[40px]'>3</div>
</div>
</div>
The first argument to setTimeout should be a function, but you’re invoking the function and passing its return value to setTimeout. Invoking it triggers the change(s) immediately.
// do this
setTimeout(() => setPageTwoVisible(false), 500)
// not this
setTimeout(setPageTwoVisible(false), 500)
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
Here's a quick rundown of the relevant code before I ask this question
The HomePage component
const Home = () => {
return (
<div>
<div>
{questions.map((question) => (
<div key={question.id} className="mb-4">
<Question
title={question.title}
contentPreview={question.contentPreview}
/>
</div>
))}
</div>
<Card className="p-4">Side Controlls</Card>
</div>
);
};
The Question component
const Question = ({ title, contentPreview }) => (
<Card className="p-4 break-words">
<h1 className="mb-4 text-lg text-blue-600">{title}</h1>
<p className="text-gray-500">{contentPreview}</p>
<div className="flex mt-4 gap-4">
<InfoIcon
icon={<HeartIcon />}
info={20}
iconClassName="text-red-400 w-6 h-6"
infoClassName="text-gray-500"
/>
<InfoIcon
icon={<CommentIcon />}
info={40}
iconClassName="text-blue-400 w-6 h-6"
infoClassName="text-gray-500"
/>
</div>
</Card>
);
The Layout component that HomePage is being wrapped in
const Layout = ({ children }) => (
<div className="bg-gray-100">
<div className="flex flex-col min-h-screen">
<NavBar />
<div className="mt-4 max-w-7xl self-center w-full px-4">{children}</div>
</div>
</div>
);
And here are some screenshots of whats happening
A screenshot with the containing div of the HomePage Component having a background so you can see better where it is
https://gyazo.com/b8aa356912f973f854299c665c66de76
A screenshot with the div that containing all the questions colored is the reddish color
and the (soon to be) controls/sidebar colored in green
https://gyazo.com/2ceb6a1277f1de4506531a2bcf0b9b17
And finally, the real problem is this screenshot, because I want both the controls and List of questions to be side by side my first instinct is to give the containing div of both of them a class of "flex" but when I do that this happens
https://gyazo.com/af6206b95dc684bbcb316a8d33362b62
and the controls get push beyond the "limits" to the right. if anyone knows or has any ideas about why this might be happening please let me know. thank you
(PS. please do not answer and say "use bootstrap" or use "x ui framework instead" because I'm using tailwind and do want to stay in tailwind)
I want both the controls and List of questions to be side by side
In such case, use flex flex-1 on both the sections to have even width. Else, you can still specify a width like question section flex w-8/12 and the side controls section flex w-4/12.
I am building a BlackJack game and I am mapping over a dealer cards array to display the dealer cards. I want to hide the first card that is returned from the array.
This is my DealerCards component.
import React from 'react'
const DealerCards = props => {
return (
<div className="text-center">
Dealer Cards
<div className="text-center m-auto flex justify-center">
{props.dealerCards.length > 0 ? (
<div className="mx-auto flex justify-center">
{props.dealerCards.map(card => (
<div key={card[0].code}>
<img
className="m-5 h-40 dealer-cards"
src={card[0].image}
alt={card[0].code}
/>
</div>
))}
</div>
) : (
<div></div>
)}
</div>
</div>
)
}
export default DealerCards
And this is the CSS I am using to try and hide it.
.dealer-cards:first-of-type {
display: none;
}
I also tried moving the dealer-cards className to the images parent div but got the same result.
What am I doing wrong??
Let me know if you need to see more of the code.
dealerCards.slice(1).map(...) will hide the first child.
You can update existing CSS style to like this,
.dealer-cards:nth-child(1) { display: none; }
I think this may help you.