Reputation: 464
I have a simple React component with two squares which are in the same absolute position. The blue square covers the red square.
function App() {
return (
<div className="App">
<div>
<div
style={{
position: "absolute",
backgroundColor: "red",
width: 100,
height: 100
}}
onMouseDown={() => console.log("Red!")}
/>
<div
style={{
position: "absolute",
backgroundColor: "blue",
width: 100,
height: 100
}}
onMouseDown={() => console.log("Blue!")}
/>
</div>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
When attaching event listeners to the react components, only the component on top catches the event and it does not reach the red square. Why is that the case? Is this default behavior? I thought event propagation is only stopped using event.stopPropagation()
? When using vanilla javascript, both squares catch the event though.
function clickRed() {
console.log("Red!");
}
function clickBlue() {
console.log("Blue!");
}
<div id="root">
<div style="position: absolute; background-color: red; min-width: 100px; min-height: 100px;" onmousedown="clickRed();" />
<div style="position: absolute; background-color: blue; min-width: 100px; min-height: 100px;" onmousedown="clickBlue();"/>
</div>
Upvotes: 0
Views: 1556
Reputation: 1073968
This isn't a React thing, it's how events work in the DOM. The issue is that events propagate through the DOM tree, from innermost children to outermost ancestors of those children. But your elements are siblings, they don't have a parent/child relationship. So whichever one is above the other in the z-order will be the one that receives the event (which then propagates to that element's parent, not its siblings).
When using vanilla javascript, both squares catch the event though.
Not with the DOM structure you've defined in your question. Here it is with straight HTML and inline event handlers:
<div class="App">
<div>
<div
style="
position: absolute;
background-color: red;
width: 100px;
height: 100px;
"
onmousedown='console.log("Red!")'
></div>
<div
style="
position: absolute;
background-color: blue;
width: 100px;
height: 100px;
"
onmousedown='console.log("Blue!")'
></div>
</div>
</div>
Or with JavaScript using the DOM directly:
const app = document.createElement("div");
app.innerHTML = `
<div>
<div
style="
position: absolute;
background-color: red;
width: 100px;
height: 100px;
"
class="red"
></div>
<div
style="
position: absolute;
background-color: blue;
width: 100px;
height: 100px;
"
class="blue"
></div>
</div>
`;
app.querySelector(".red").addEventListener("mousedown", () => console.log("Red!"));
app.querySelector(".blue").addEventListener("mousedown", () => console.log("Blue!"));
document.getElementById("root").appendChild(app);
<div id="root"></div>
Re your edit adding this example:
function clickRed() {
console.log("Red!");
}
function clickBlue() {
console.log("Blue!");
}
<div id="root">
<div style="position: absolute; background-color: red; min-width: 100px; min-height: 100px;" onmousedown="clickRed();" />
<div style="position: absolute; background-color: blue; min-width: 100px; min-height: 100px;" onmousedown="clickBlue();"/>
</div>
The HTML there is incorrect. In HTML, <div/>
is exactly the same thing as <div>
— it's just a start tag. As a result, your div
elements are nested (blue is inside red). The HTML equivalent to JSX <div/>
is <div></div>
:
function clickRed() {
console.log("Red!");
}
function clickBlue() {
console.log("Blue!");
}
<div id="root">
<!-- Scroll right in the stack snippet to see the difference at the end ⇒ ⇒ ⇩⇩⇩⇩⇩⇩⇩ -->
<div style="position: absolute; background-color: red; min-width: 100px; min-height: 100px;" onmousedown="clickRed();" ></div>
<div style="position: absolute; background-color: blue; min-width: 100px; min-height: 100px;" onmousedown="clickBlue();"></div>
</div>
Upvotes: 3