Reputation: 317
I am attempting to overlay a div on top of an image when a user clicks on the image in React. I have managed to append the div to any other element on my page, but for some reason it will not work on the image.
Here is the entire component in question:
function Home() {
const openTargetingBox = (e) => {
if (e.target.className === 'test') {
const newDiv = document.createElement('div');
newDiv.setAttribute("class", "targeting-box");
document.querySelector('.test').appendChild(newDiv);
}
};
useEffect(() => {
document.querySelector(".test").addEventListener("click", openTargetingBox)
});
return (
<Layout>
<div className="main-container">
<div className="main-container__grid">
<img src={img} className="test"></img>
</div>
</div>
</Layout>
);
}
export default Home;
and here is the associated CSS:
.test {
position: relative;
z-index: 0;
}
.test:hover {
cursor: url(./crosshair.svg) 21 21, crosshair;
}
.targeting-box {
position: absolute;
width: 50px;
height: 50px;
background-color: blueviolet;
left: 0;
top: 0;
z-index: 1;
}
As I mentioned above, if I switch the query selector within openTargetingBox
so that it selects another div on my page, I can see the div being appended to it when the image is clicked.
When trying to append the div over the image, I can see that the div is being appended to the image, but it is not visible - perhaps behind it? I have set z-index
within the CSS with relative positioning on the parent element, but that doesn't work either.
Any ideas would be highly appreciated!
Upvotes: 2
Views: 7176
Reputation: 7915
I second Domonik that there are much more elegant tools at your disposal in React to accomplish this. But if you're bent on doing it this way, Here is how.
Change this:
document.querySelector('.test').appendChild(newDiv);
to
document.querySelector(".main-container__grid").appendChild(newDiv);
Also, I would suggest moving your openTargetingBox
function out of the component, since there is no need for it in there.
And finally, I suggest using a dependency array in useEffect
. Just go with an empty array so your addEventListener
is only called on load. I do realize that you don't update any states so it will be called once anyway, but just for future reference...
useEffect(() => {
document.querySelector(".test").addEventListener("click", openTargetingBox);
}, []);
Sandbox: https://codesandbox.io/s/dawn-fog-spudv?file=/src/App.js
Upvotes: 2
Reputation: 6313
The way you add the div and add your event listener is not very React-like. Instead try to use state and the power of react.
The main reason your code doesn't work is because you can't really append a child to an image tag as image tags don't have children.
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://via.placeholder.com/150"
className="test"
alt="Placeholder"
onClick={() => setShowOverlay(true)}
/>
{showOverlay && <div className="targeting-box" />}
</div>
</div>
</div>
);
}
export default Home;
I made a small codesandbox to show how this would work.
Upvotes: 1