React Mouse Events

In the last lesson you learned about React Keyboard Events, so you can already react when someone types. Now let’s handle the mouse, so you can build hover effects, tooltips, and things that follow the pointer, not just clicks.

🤔 Why do we need mouse events?

Here’s the pain. A plain click handler only fires on one action. Real interfaces need to respond to much more.

  • A button should change color when the pointer moves over it, before any click happens.
  • A tooltip should appear when you hover, then disappear when you move away.
  • A drawing app needs to know where the pointer is as it moves across the screen.
  • Some actions only make sense on a double-click, like opening an item.

So clicks alone are not enough. Mouse events let your component respond to hovering, moving, and double-clicking too, not just a single tap.

🧩 What are mouse events?

Mouse events are the messages React sends your component whenever the pointer does something on an element.

  • They work just like onClick. You add a prop with a function, and React calls it when that thing happens.
  • Each one is named for the action: onMouseEnter, onMouseLeave, onMouseMove, onDoubleClick, and more.
  • React passes your function an event object, usually called e. It holds details like where the pointer is.
  • The names use camelCase, so it’s onMouseEnter, not onmouseenter.

Here is the general shape. You attach a handler to an element, and React runs it when the event fires.

function Box() {
const handleEnter = () => {
console.log("The pointer came in!");
};
return <div onMouseEnter={handleEnter}>Hover over me</div>;
}

So whenever the pointer moves onto that div, React calls handleEnter. Every other mouse event follows this same pattern.

🖱️ Hover with onMouseEnter and onMouseLeave

The most common thing you’ll build is a hover effect. For that you need two events working together.

  • onMouseEnter fires once when the pointer moves onto the element.
  • onMouseLeave fires once when the pointer moves off the element.
  • Pair them with a piece of state, like isHovered, to remember whether the pointer is currently on top.

Here we keep an isHovered flag in state. We flip it to true on enter and back to false on leave, then use it to change the background color.

import { useState } from "react";
function HoverBox() {
const [isHovered, setIsHovered] = useState(false);
return (
<div
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
style={{ background: isHovered ? "skyblue" : "lightgray", padding: "20px" }}
>
{isHovered ? "Thanks for hovering!" : "Hover over me"}
</div>
);
}

Let’s walk through what happens.

  • The pointer moves onto the box, so onMouseEnter runs and sets isHovered to true.
  • State changed, so React re-renders. The background turns sky blue and the text updates.
  • The pointer moves off, so onMouseLeave runs and sets isHovered back to false. The box returns to gray.

This same pattern is how you show a tooltip on hover. You just render the tooltip when isHovered is true.

onMouseEnter vs onMouseOver

There are also onMouseOver and onMouseOut. They look similar, but they bubble — they also fire when the pointer moves over child elements inside. onMouseEnter and onMouseLeave do not bubble, so they fire only for the element itself. That makes them the cleaner choice for hover effects.

📍 Tracking the pointer with onMouseMove

Sometimes you need the exact spot of the pointer, not just that it’s over the element. That’s what onMouseMove is for.

  • onMouseMove fires again and again as the pointer moves across the element.
  • The event object gives you the position. e.clientX is the horizontal position and e.clientY is the vertical one.
  • Both are measured in pixels from the top-left corner of the visible page.

Here we read e.clientX and e.clientY on every move and store them in state, so we can show the live position.

import { useState } from "react";
function MouseTracker() {
const [pos, setPos] = useState({ x: 0, y: 0 });
const handleMove = (e) => {
setPos({ x: e.clientX, y: e.clientY });
};
return (
<div onMouseMove={handleMove} style={{ height: "200px", background: "lightyellow" }}>
The pointer is at {pos.x}, {pos.y}
</div>
);
}

So as you move inside the yellow area, the numbers update in real time.

  • Each move fires handleMove, which reads the new position and saves it to state.
  • State changed, so React re-renders and the text shows the latest spot.

clientX vs pageX

e.clientX and e.clientY are measured from the visible window. If you scroll the page, use e.pageX and e.pageY instead, because those include the scrolled distance. For most small components, clientX and clientY are what you want.

🖱️🖱️ Reacting to a double-click

A single click and a double-click are different actions, and React keeps them separate. For two quick clicks in a row, you use onDoubleClick.

  • onDoubleClick fires when the user clicks twice quickly on the same element.
  • It’s handy for actions like opening an item or starting an edit, while a single click does something lighter.
  • You attach it exactly like onClick, with a function.

Here a single click and a double-click each update a message, so you can feel the difference.

import { useState } from "react";
function ClickDemo() {
const [message, setMessage] = useState("Try clicking");
return (
<button
onClick={() => setMessage("Single click")}
onDoubleClick={() => setMessage("Double click!")}
>
{message}
</button>
);
}

So one click shows “Single click”, and two quick clicks show “Double click!”. The onDoubleClick event is what catches that fast second tap.

⬇️⬆️ A quick word on onMouseDown and onMouseUp

A click is really two smaller steps, and React lets you listen to each one on its own.

  • onMouseDown fires the moment the mouse button is pressed down.
  • onMouseUp fires the moment the button is released.
  • A normal onClick is really a down followed by an up on the same element.

You won’t need these every day, but they have their moments.

  • They’re useful for drag-and-drop, where you start an action on onMouseDown and finish it on onMouseUp.
  • For most clicks, plain onClick is still the right tool.

Don't reach for these too early

For ordinary buttons and links, stick with onClick. Only use onMouseDown and onMouseUp when you genuinely need the press and release as separate steps, like dragging something. Otherwise you’ll write more code than you need.

🧩 What You’ve Learned

  • ✅ Mouse events let your component react to hovering, moving, and double-clicking, not just clicks
  • onMouseEnter and onMouseLeave fire when the pointer moves onto and off an element, perfect for hover effects
  • ✅ Pair them with a state flag like isHovered to change styles or show a tooltip
  • onMouseEnter and onMouseLeave do not bubble, unlike onMouseOver and onMouseOut
  • onMouseMove fires as the pointer moves, and e.clientX and e.clientY give you its position
  • onDoubleClick catches two quick clicks for actions like opening an item
  • onMouseDown and onMouseUp split a click into press and release, useful for drag-and-drop

Check Your Knowledge

Test what you learned. Pick an answer for each question, then click Check.

  1. 1

    Which two events are best for building a hover effect?

    Why: onMouseEnter fires when the pointer moves onto the element and onMouseLeave fires when it moves off. Together they track whether the pointer is currently hovering.

  2. 2

    How do you read the pointer's position inside an onMouseMove handler?

    Why: The event object carries e.clientX for the horizontal position and e.clientY for the vertical position, measured in pixels from the top-left of the visible window.

  3. 3

    Why are onMouseEnter and onMouseLeave preferred over onMouseOver and onMouseOut for hover?

    Why: onMouseOver and onMouseOut bubble, so they also fire when the pointer moves over child elements inside. onMouseEnter and onMouseLeave do not bubble, which makes hover logic cleaner.

  4. 4

    Which event would you use to run code only when the user clicks twice quickly?

    Why: onDoubleClick fires when the user clicks twice quickly on the same element, which is useful for actions like opening an item or starting an edit.

🚀 What’s Next?

Now you can handle hovering, moving, and double-clicking with the mouse. But sometimes an event triggers the browser’s own default behavior that you don’t want, like a form reloading the page. Next you’ll learn how to stop that.

React Preventing Default Behavior

Share & Connect