Busca en todas las páginas de la documentación
Maneja clics, doble clic, pasos del ratón y movimiento del ratón en componentes React.
| Prop React | Tipo TypeScript | Se Dispara Cuando |
|---|---|---|
onClick | React.MouseEvent<T> | El elemento se hace clic (mousedown + mouseup en el mismo objetivo) |
onDoubleClick | React.MouseEvent<T> | El elemento se hace doble clic |
onMouseDown | React.MouseEvent<T> | Se presiona el botón del ratón en el elemento |
onMouseUp | React.MouseEvent<T> | Se suelta el botón del ratón en el elemento |
onMouseEnter | React.MouseEvent<T> | El puntero entra al elemento (NO se propaga) |
onMouseLeave | React.MouseEvent<T> | El puntero sale del elemento (NO se propaga) |
onMouseOver | React.MouseEvent<T> | El puntero entra al elemento o a un hijo (se propaga) |
onMouseOut | React.MouseEvent<T> | El puntero sale del elemento o entra a un hijo (se propaga) |
onMouseMove | React.MouseEvent<T> | El puntero se mueve sobre el elemento |
onContextMenu | React.MouseEvent<T> | Se hace clic derecho o se presiona la tecla del menú contextual |
Tarjeta de referencia rápida -- lista para copiar y pegar.
// Manejador de clic con evento tipado
function ClickExample() {
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
console.log("Haz clic en", e.clientX, e.clientY);
};
return <button onClick=
Cuándo usarlo: Necesitas responder a interacciones del ratón -- clics, pasos del ratón, clics derechos o rastreo de posición -- en un componente cliente.
"use client";
import { useState, useRef, useCallback } from "react";
type ContextMenuState = {
visible: boolean;
x: number;
y: number;
};
export default function InteractiveCard
Lo que esto demuestra:
onClick, onMouseEnter, onMouseLeave y onContextMenu en un solo elementogetBoundingClientRecte.stopPropagation() para prevenir que los clics de elementos del menú disparen el manejador de clic de la tarjetae.preventDefault() en onContextMenu para suprimir el menú predeterminado del navegadorReact.MouseEvent<T> que envuelve el MouseEvent nativo con una interfaz consistente entre navegadores.onMouseEnter y onMouseLeave NO se propagan. Se disparan solo para el elemento exacto, no sus hijos. Usa onMouseOver y onMouseOut si necesitas comportamiento de propagación.setTimeout), lee primero los valores que necesitas en variables locales.Clic con paso de datos:
type Item = { id: string; name: string };
function ItemList({ items }: { items: Item[] }) {
const handleClick = (item: Item) =>
Rastreo de pasos del ratón con coordenadas:
function HoverTracker() {
const [position, setPosition] = useState({ x: 0, y: 0 });
const handleMouseMove = useCallback(
(e: React.MouseEvent<HTMLDivElement>) =>
Detección de arrastre inicial (mousedown + threshold de mousemove):
function DragDetector() {
const startPos = useRef<{ x: number; y: number } | null>(null);
const [dragging, setDragging] = useState(false);
Detección de pulsación larga:
function LongPressButton({ onLongPress }: { onLongPress: () => void }) {
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const handleMouseDown = ()
Menú contextual de clic derecho con portal:
import { createPortal } from "react-dom";
function ContextMenuPortal({
x,
y,
onClose,
}: {
x: number;
y: number;
onClose: () =>
// El genérico T especifica el tipo de elemento para e.currentTarget
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
e.currentTarget; // HTMLButtonElement -- el elemento al que se adjunta el manejador
e.target; // EventTarget -- el elemento realmente hecho clic (podría ser un hijo)
};
// Usa HTMLElement como fallback genérico cuando el elemento exacto varía
const handleAny = (e
onMouseEnter/onMouseLeave vs onMouseOver/onMouseOut -- onMouseEnter y onMouseLeave NO se propagan y NO se disparan al moverse entre elementos hijos. onMouseOver y onMouseOut SÍ se propagan, por lo que se disparan al entrar/salir de hijos también. Usar el par incorrecto y los estados de pasos del ratón parpadearán en elementos anidados.
Crear nuevas funciones flecha en JSX en cada renderizado -- Escribir onClick={() => handleClick(id)} crea una nueva referencia de función cada renderizado, lo cual puede causar re-renderizados innecesarios en componentes hijos que dependen de igualdad referencial. Solución: Usa useCallback o extrae el manejador a una referencia estable. Para listas, considera un componente hijo que reciba el elemento y adjunte su propio manejador.
onClick se dispara en CUALQUIER botón del ratón por defecto -- El onClick de React se dispara solo para clics izquierdos en la mayoría de navegadores, pero no se garantiza para todos los elementos y navegadores. Si necesitas distinguir botones, verifica e.button en onMouseDown u onMouseUp.
Confusión entre e.target y e.currentTarget -- e.target es el elemento que fue realmente hecho clic (podría ser un hijo). e.currentTarget es el elemento al que se adjunta el manejador. Si haces clic en un <span> dentro de un <button>, e.target es el span, e.currentTarget es el button. Acceder a propiedades como .value o .dataset en e.target requiere estrechamiento de tipo.
onDoubleClick se dispara dos eventos onClick primero -- Un doble clic desencadena: onClick -> onClick -> onDoubleClick. Si tu manejador onClick realiza una acción, obtendrás esa acción dos veces antes de que se dispare el doble clic. Solución: Usa un temporizador de debounce para distinguir clics simples de dobles, o evita combinar ambos en el mismo elemento.
Los eventos sintéticos se anulan después del manejador -- Acceder a e.clientX dentro de un setTimeout o después de un await devuelve null porque React recicla el objeto de evento. Solución: Lee valores en variables locales antes de cualquier operación asincrónica: const x = e.clientX;.
-- Adjuntar actualizaciones de estado a puede causar cientos de re-renderizados por segundo. Throttle con o una utilidad de throttle, o usa una ref para almacenar posición y solo re-renderiza cuando sea necesario.
| Alternativa | Úsalo Cuando | No lo Uses Cuando |
|---|---|---|
Pointer Events (onPointerDown, etc.) | Necesitas soportar touch, pen y mouse de forma uniforme | Solo apuntas a mouse en desktop |
CSS :hover | Solo estilos hover, no se necesita lógica JS | Necesitas rastrear estado de hover o coordenadas en JS |
Drag and Drop API (onDragStart, etc.) | Necesitas arrastrar y soltar completo con transferencia de datos | Solo necesitas detección de movimiento al hacer clic y arrastrar |
addEventListener en useEffect | Necesitas listeners globales (por ejemplo, rastreo de ratón a nivel de documento) | El evento está limitado a un elemento específico |
| Librerías de terceros (dnd-kit, Framer Motion) | Arrastrar complejo, gestos o animación vinculada a la posición del ratón | Manejadores simples de clic o pasos del ratón |
onMouseEnter / onMouseLeave NO se propagan y se disparan solo para el elemento exacto, no sus hijosonMouseOver / onMouseOut SÍ se propagan, por lo que se disparan al entrar/salir de elementos hijos tambiénEnter/Leave para estado de pasos del ratón en un solo elemento; usa Over/Out cuando necesites propagacióne.target es el elemento que fue realmente hecho clic (podría ser un hijo anidado)e.currentTarget es el elemento al que se adjunta el manejador<span> dentro de un <button>, e.target es el span, e.currentTarget es el buttonUsa e.button en onMouseDown u onMouseUp:
0 = botón izquierdo1 = botón central2 = botón derechoNo confíes en onClick para detección de botones -- es principalmente para clics izquierdos.
const handleContextMenu = (e: React.MouseEvent<HTMLDivElement>) => {
e.preventDefault(); // suprime menú predeterminado del navegador
setMenu({ visible: true, x: e.clientX, y: e.clientY });
};
return <div onContextMenu=Un doble clic desencadena: onClick -> onClick -> onDoubleClick. Si tu onClick realiza una acción, se ejecuta dos veces antes de que se dispare el doble clic. Usa un temporizador de debounce para distinguir clics simples de dobles, o evita combinar ambos manejadores en el mismo elemento.
Los eventos sintéticos de React se anulan después de que el manejador regresa. Acceder a propiedades más tarde da null. Lee valores en variables locales antes de cualquier operación asincrónica: const x = e.clientX;.
function ItemList({ items }: { items: Item[] }) {
const handleClick = (item: Item) =>
(e: React.MouseEvent<HTMLLIElement>) =>
onMouseMove se dispara muy frecuentemente (cientos de veces por segundo). Adjuntar actualizaciones de estado a él causa re-renderizados excesivos. Throttle con requestAnimationFrame, usa una utilidad de throttle, o almacena posición en una ref y solo re-renderiza cuando sea necesario.
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const handleMouseDown = () => {
timerRef.current = setTimeout(onLongPress, 600);
};
const handleMouseUp
clientX / clientY -- relativo al viewportpageX / pageY -- relativo al documento (incluye offset de desplazamiento)screenX / screenY -- relativo al monitornativeEvent.offsetX / offsetY -- relativo al elemento objetivo// Tipo de elemento específico
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
e.currentTarget; // HTMLButtonElement
};
// Fallback genérico para cualquier elemento HTML
const handleAny = (e: React.
const handleDelegated = (e: React.MouseEvent<HTMLUListElement>) => {
// e.target se tipifica como EventTarget, no Element
const target = e.target as HTMLElement;
if (target.tagName === "LI") {
console.
onMouseMove se dispara muy frecuentementeonMouseMoverequestAnimationFramePara mejor desempeño, extrae cada elemento en un componente hijo con su propio manejador estable.