How do I create an overlay in React? - javascript

I am currently trying to create an overlay on an image when hovering. I am able to get a box displayed on screen but it's not placed over the image.
featured.js
const Featured = ({ images }) => {
if (!images || !Array.isArray(images)) return null;
return (
<section className={styles.featuredWrapper} id="work">
{images.map((image) => {
return (
<div className={styles.wrap}>
<GatsbyImage
image={image.gatsbyImageData}
alt="Link to the alt text"
className={styles.featuredImg}
/>
<div className={styles.featuredOverlay}>Test</div>
</div>
);
})}
</section>
);
};
featured.module.css
.featuredImg {
width: 100%;
position: relative;
}
.featuredOverlay {
position: absolute;
background: black;
opacity: 0.5;
width: 100%;
height: 100%;
z-index: 1;
}
Every explanation I see revolves around the use of positions absolute and relative which makes me think my issue is how I am rendering my component. Am I using the position properties on the wrong elements?

import { useState } from "react";
import "./styles.css";
function Home() {
const [showOverlay, setShowOverlay] = useState(false);
return (
<div>
<div className="main-container">
<div className="main-container__grid">
<img
src="https://miro.medium.com/max/2000/1*3SjDVyFY09xZ7NYMO5kj0g.png"
className="test"
alt="Placeholder"
onHover={() => setShowOverlay(true)}
/>
{showOverlay && <div className="targeting-box" />}
</div>
</div>
</div>
);
}
export default Home;

Related

Make list items assume height of largest list item [duplicate]

This question already has answers here:
Equal height rows in CSS Grid Layout
(2 answers)
Closed 4 days ago.
I have a group of list items that are essentially containers with some text content. On mobile screen dimensions, I want the height of the containers to be set automatically according to the text content. However, I want all of the containers to assume the same height. So in this case, each container height would equal the height of the tallest container. The codesandbox link is here.
As you can see in the screenshot below, on a 414 px screen, the third container in the list is taller than the other two. I want all the containers to assume the height of the third one so that they can be the same.
How can I accomplish this? Here is the relevant lines of code:
<div className="App">
<h1>Lender Benefits</h1>
<ul className="list">
{lenderBenefits.map((benefit) => (
<li className="benefit_container">{benefit}</li>
))}
</ul>
</div>
.list {
padding-left: 0;
width: 100%;
}
.benefit_container {
/* height: max-content; */
border-radius: 24px;
margin-bottom: 12px;
padding: 2px 8px;
font-size: 16px;
font-weight: 600;
background-color: #f1e8dc;
display: flex;
align-items: center;
}
The CSS Grid approach (preferred):
const styleForEqualHeightRows = {
display: "grid",
gridAutoRows: "1fr",
gap: "1rem" // <= Optional
}
export default function App() {
return (
<div className="App">
<h1>Lender Benefits</h1>
<ul
className="list"
style={styleForEqualHeightRows}
>
{lenderBenefits.map((benefit) => (
<li
key={benefit}
className="benefit_container"
>
{benefit}
</li>
))}
</ul>
</div>
);
}
Here's one (hacky) approach using JavaScript:
import { useLayoutEffect, useRef, useState } from "react";
import "./styles.css";
const lenderBenefits = [
"No repayment, just reduced margins through credit",
"A cash advance without predatory interest",
"Works with your community to bring them in on your mission"
];
export default function App() {
const list = useRef();
const [style, setStyle] = useState({});
useLayoutEffect(() => {
async function handleResize() {
await setStyle({}); // Break from batch updates...
const lis = list.current.querySelectorAll("li");
const heights = [...lis].map((li) => li.offsetHeight);
const maxHeight = Math.max(...heights);
setStyle({ height: maxHeight + "px" });
}
handleResize();
window.addEventListener("resize", handleResize);
return function cleanUp() {
window.removeEventListener("resize", handleResize);
};
}, []);
return (
<div className="App">
<h1>Lender Benefits</h1>
<ul ref={list} className="list">
{lenderBenefits.map((benefit) => (
<li key={benefit} style={style} className="benefit_container">
{benefit}
</li>
))}
</ul>
</div>
);
}

How to change css property in react

I want to change css width property of my element on some condition
<div className="consoleLayoutRoot-sideMenu">
<ConsoleSideMenu />
</div>
css
.consoleLayoutRoot-sideMenu .ant-menu {
padding-top: 30px;
/* background-color: #191146 !important; */
}
I am doing this way..but nothing is happening
document.getElementsByClassName("conjnjnot-sideMenjnjbhbhu.annjn ").style.width = "77px";
That's not working because you're treating a list as though it were an element. But it's also fundamentally not how you would do this in a React project.
Instead, you'd have the component re-render when the condition becomes true (perhaps by setting a state member). When rendering the div, you optionally include a style or a class name depending on whether you want the width applied:
<div className={`consoleLayoutRoot-sideMenu ${shouldHaveWidthClass ? "width-class" : ""}`}>
<ConsoleSideMenu />
</div>
...where .width-class { width: 50px; } is in your stylesheet.
Or with inline style, but inline styles are best avoided:
<div className="consoleLayoutRoot-sideMenu" style={shouldHaveWidthSetting ? { width: "50px" } : undefined}>
<ConsoleSideMenu />
</div>
Here's an example (using a class);
const {useState} = React;
const ConsoleSideMenu = () => <span>x</span>;
const Example = () => {
const [includeWidth, setIncludeWidth] = useState(false);
const toggle = ({currentTarget: { checked }}) => {
setIncludeWidth(checked);
};
return <React.Fragment>
<div className={`consoleLayoutRoot-sideMenu ${includeWidth ? "width-class" : ""}`}>
<ConsoleSideMenu />
</div>
<label>
<input type="checkbox" onChange={toggle} checked={includeWidth} />
Include width class
</label>
</React.Fragment>;
};
ReactDOM.render(<Example />, document.getElementById("root"));
.width-class {
width: 50px;
}
.consoleLayoutRoot-sideMenu {
border: 1px solid blue;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>

Focused elements display wrong style

I have element with width 400% and I want to move it to left by using translateX(-(index/4)*100%) when focused index changes.
Changing focused element translateX property with tab keyboard button displays it wrong on middle elements (1,2) even though using same hardcoded styling works as expected. What am I missing here?
const {useState} = React;
const App = () => {
const [curr, setCurr] = useState(0);
const carouselStyles = {
transform: `translateX(${-(curr / 4) * 100}%)`
// uncomment to see that styling works fine with hardcoded values 1,2..
// transform: `translateX(${-(1 / 4) * 100}%)`
};
const handleFocus = (num) => {
if (num !== curr) {
setCurr(num);
}
};
console.log(carouselStyles);
return (
<div>
<div className="carousel" style={carouselStyles}>
<div className="item">
11 very long text
<a href="/111" onFocus={() => handleFocus(0)}>
11111
</a>
</div>
<div className="item">
22 very long text
<a href="/222" onFocus={() => handleFocus(1)}>
22222
</a>
</div>
<div className="item">
33 very long text
<a href="/333" onFocus={() => handleFocus(2)}>
33333
</a>
</div>
<div className="item">
44 very long text
<a href="/444" onFocus={() => handleFocus(3)}>
44444
</a>
</div>
</div>
current: {curr}
</div>
);
}
// Render it
ReactDOM.render(
<App />,
document.getElementById("react")
);
.carousel {
display: flex;
align-items: center;
width: 400%;
}
.item {
flex: 0 1 100%;
text-align: center;
border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
I needed to prevent the scrolling and in my provided example its enough to add this line into handleFocus function
window.scrollTo(0, 0);
But in my real scenario parent wrapper also had overflow: hidden; which prevented above code from working. So I've used refs
const handleFocus = (num) => {
if (num !== curr) {
setCurr(num);
carouselRef.current.scrollTo(0, 0);
}
};
return (
<div ref={carouselRef}>
<div className="carousel" style={carouselStyles}>
...
</div>
current: {curr}
</div>
);

React component that zooms into an image while keeping dimensions on mouse over - React + Bootstrap

So I have been looking all over the place over the past few days and cannot find anything that works. I am using React with Bootstrap. I want a stateless functional component that takes an image path and returns an img element which, when hovered over by the mouse, zooms into the image while keeping the dimensions of the element the same.
I have tried:
Changing the style attribute in the onMouseOver and onMouseOut events like so
import React from "react";
const ImageHoverZoom = ({ imagePath }) => {
return (
<img
src={imagePath}
alt=""
style={{ overflow: "hidden" }}
onMouseOver={(e) => (e.currentTarget.style = { transform: "scale(1.25)", overflow: "hidden" })}
onMouseOut={(e) => (e.currentTarget.style = { transform: "scale(1)", overflow: "hidden" })}
/>
);
};
export default ImageHoverZoom;
Creating a custom css class and applying that to the img element.
index.css:
.hover-zoom {
overflow: hidden;
}
.hover-zoom img {
transition: all 0.3s ease 0s;
width: 100%;
}
.hover-zoom img:hover {
transform: scale(1.25);
}
imageHoverZoom.jsx:
import React from "react";
const ImageHoverZoom = ({ imagePath }) => {
return (
<img
src={imagePath}
alt=""
className="hover-zoom"
/>
);
};
export default ImageHoverZoom;
I have also tried a class component with state
import React, { Component } from "react";
class ImageHoverZoom extends Component {
state = {
path: this.props.imagePath,
mouseOver: false,
};
render() {
const { path, mouseOver } = this.state;
return (
<img
className={`img-fluid w-100`}
src={path}
onMouseOver={() => this.setState({ mouseOver: true })}
onMouseOut={() => this.setState({ mouseOver: false })}
style={
mouseOver
? { transform: "scale(1.25)", overflow: "hidden"}
: { transform: "scale(1)", overflow: "hidden"}
}
alt=""
/>
);
}
}
I would ideally not like to use state as I know it gets updated asynchronously and I feel like that would lead to some lag on the client side when mousing over the image. Any help is much obliged, thank you in advance!
EDIT:
I tried Rahul's answer below in my project, as well as in a brand new project. Here are the relevant (I think) files. Same thing as before. No change on mouse over.
App.js
import "./App.css";
import ImageHoverZoom from "./common/imageHoverZoom";
function App() {
return <ImageHoverZoom imagePath="http://picsum.photos/400/600" />;
}
export default App;
imageHoverZoom.jsx
import React from "react";
const ImageHoverZoom = ({ imagePath }) => {
return (
<div className="img-wrapper">
<img src={imagePath} alt="" className="hover-zoom" />
</div>
);
};
export default ImageHoverZoom;
index.css
.img-wrapper {
overflow: hidden;
}
.hover-zoom img:hover {
transform: scale(1.25);
}
Wrap the img tag in a div and then hide the overflow from div:
const ImageHoverZoom = ({ imagePath }) => {
return (
<div className="img-wrapper">
<img
src={imagePath}
alt=""
className="hover-zoom"
/>
</div>
);
};
export default ImageHoverZoom;
add the styling to img-wrapper:
.img-wrapper{
overflow:hidden;
}
img.hover-zoom:hover {
transform: scale(1.25);
}
So I solved it with Rahul's help (Thank you!). The css notation was flipped, like Rahul suggested, and to prevent the width from changing I had to set width: 100% in img.hover-zoom
Here is the component:
const ImageHoverZoom = ({ imagePath }) => {
return (
<div className="img-wrapper">
<img src={imagePath} alt="" className="hover-zoom" />
</div>
);
};
export default ImageHoverZoom;
index.css:
.img-wrapper {
overflow: hidden;
}
img.hover-zoom {
transition: all 0.3s ease 0s;
width: 100%;
}
img.hover-zoom:hover {
transform: scale(1.25);
}

displaying child div on hover on parent div in react js

Hello :) I am relatively new to react js, i am trying to apply animation on a div that is a child of another div, parent div " portfolio-product-item " displays featured image extracted from wp rest api, and child div " portfolio-product-item-details " has the contents of the post.
What i want to do is display the content when hovered over the featured image in parent div , my code is like this , how can i achieve it?
import React from 'react';
import Home from './Home';
require ('../../app.css');
require ('../../animate.min.css');
class Portfolio extends React.Component{
render(){
console.log(this.props.data.length);
var contents=[];
for (var i = 0; i < this.props.data.length; i++) {
contents.push(
<div className="col-xs-12 col-md-4">
<div id="portfolio-product-item" >
<img src={this.props.data[i].featured_image} />
<div ref= "productDetails" id ="portfolio-product-item-details" dangerouslySetInnerHTML={{__html: this.props.data[i].content.rendered}} />
</div>
</div>
);
}
return(
<div className = "container">
<div className="row">
<section className="portfolio">
<h1>Our Latest Work</h1>
<p id="below-header">These are some of the works that has been keeping us busy over the years. See for yourself what we can do.</p>
<div className="col-xs-12 ">
{contents}
</div>
</section>
</div>
</div>
)
}
}
export default Portfolio;
React allows to add / remove elements from the virtual DOM. Use the onMouseEnter and onMouseLeave to set show / hide state.
<img
onMouseEnter={() => this.setState({ show: true })}
onMouseLeave={() => this.setState({ show: false })}
/>
Then show / hide details based on the state:
{this.state.show ?
<div ref= "productDetails" id ="portfolio-product-item-details"
dangerouslySetInnerHTML={{__html: this.props.data[i].content.rendered}}
/>
: null}
My solution was something like this
import React from 'react';
import Home from './Home';
require ('../../app.css');
require ('../../animate.min.css');
class Portfolio extends React.Component{
render(){
var contents=[];
for (var i = 0; i < this.props.data.length; i++) {
var productImage ={
backgroundImage:'url('+ this.props.data[i].featured_image + ')',
backgroundSize: '100% 100%'
}
contents.push(
<div className="col-xs-12 col-md-6 col-lg-4">
<div id="portfolio-product-item" style ={productImage} >
<div ref= "productDetails" id ="portfolio-product-item-details" dangerouslySetInnerHTML={{__html: this.props.data[i].content.rendered}} />
</div>
</div>
);
}
return(
<div className = "container">
<div className="row">
<section className="portfolio">
<h1>Our Latest Work</h1>
<p id="below-header">These are some of the works that has been keeping us busy over the years. See for yourself what we can do.</p>
<div className="col-xs-12 ">
{contents}
</div>
</section>
</div>
</div>
)
}
}
export default Portfolio;
and css rules were like this
section.portfolio div#portfolio-product-item{
height:370px;
width:100%;
background: #f0f0f0;
margin:15px;
position:relative;
transform: rotate(4deg) ;
box-shadow: 5px 5px 5px #909090;
-webkit-font-smoothing: antialiased;
}
section.portfolio div#portfolio-product-item-details{
height:100%;
width:100%;
padding:10px;
text-align: center;
color:#ffffff;
position: absolute;
top:0;
background-color: #000000;
opacity:0;
}
section.portfolio div#portfolio-product-item-details:hover{
cursor:pointer;
opacity:0.9;
transition: all .5s ease-in-out;
}

Categories