Hooks
No hooks found in any category.
useHover
sensorsInstallation
npx usehooks-cli@latest add use-hover
Description
A React hook for detecting when an element is being hovered with optional callbacks, delay support, and TypeScript generics for element types.
Parameters
Name | Type | Default | Description |
---|---|---|---|
options? | UseHoverOptions | {} | Configuration options for hover behavior |
Return Type
UseHoverReturn<T>
Property | Type | Description |
---|---|---|
isHovered | boolean | Whether the element is currently being hovered |
ref | React.RefObject<T> | Ref to attach to the element you want to detect hover on |
Examples
Basic Hover Detection
Simple hover state detection
1const { isHovered, ref } = useHover();
2
3return (
4 <div
5 ref={ref}
6 style={{
7 padding: '20px',
8 backgroundColor: isHovered ? 'lightblue' : 'lightgray'
9 }}
10 >
11 {isHovered ? 'Hovered!' : 'Hover me'}
12 </div>
13);
With Callbacks and Delay
Using hover with callbacks and delay
1const { isHovered, ref } = useHover({
2 onHoverStart: () => console.log('Hover started'),
3 onHoverEnd: () => console.log('Hover ended'),
4 delay: 300 // 300ms delay
5});
6
7return (
8 <button ref={ref}>
9 {isHovered ? 'Hovering...' : 'Hover me (with delay)'}
10 </button>
11);
Dependencies
react
Notes
- •Automatically cleans up event listeners on unmount
- •Supports delay for hover start but immediate hover end
- •Uses TypeScript generics for type-safe element references
- •Handles timeout cleanup to prevent memory leaks
Implementation
1'use client';
2
3import { useState, useCallback, useRef, useEffect } from "react";
4
5interface UseHoverOptions {
6 onHoverStart?: () => void;
7 onHoverEnd?: () => void;
8 delay?: number;
9}
10
11interface UseHoverReturn<T extends HTMLElement = HTMLElement> {
12 isHovered: boolean;
13 ref: React.RefObject<T>;
14}
15
16export const useHover = <T extends HTMLElement = HTMLElement>(
17 options: UseHoverOptions = {}
18): UseHoverReturn<T> => {
19 const [isHovered, setIsHovered] = useState(false);
20 const ref = useRef<T>(null);
21 const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
22
23 const { onHoverStart, onHoverEnd, delay = 0 } = options;
24
25 const handleMouseEnter = useCallback(() => {
26 if (timeoutRef.current) {
27 clearTimeout(timeoutRef.current);
28 timeoutRef.current = null;
29 }
30
31 if (delay > 0) {
32 timeoutRef.current = setTimeout(() => {
33 setIsHovered(true);
34 onHoverStart?.();
35 }, delay);
36 } else {
37 setIsHovered(true);
38 onHoverStart?.();
39 }
40 }, [onHoverStart, delay]);
41
42 const handleMouseLeave = useCallback(() => {
43 if (timeoutRef.current) {
44 clearTimeout(timeoutRef.current);
45 timeoutRef.current = null;
46 }
47
48 setIsHovered(false);
49 onHoverEnd?.();
50 }, [onHoverEnd]);
51
52 useEffect(() => {
53 const element = ref.current;
54 if (!element) return;
55
56 element.addEventListener("mouseenter", handleMouseEnter);
57 element.addEventListener("mouseleave", handleMouseLeave);
58
59 return () => {
60 element.removeEventListener("mouseenter", handleMouseEnter);
61 element.removeEventListener("mouseleave", handleMouseLeave);
62
63 if (timeoutRef.current) {
64 clearTimeout(timeoutRef.current);
65 }
66 };
67 }, [handleMouseEnter, handleMouseLeave]);
68
69 // Cleanup timeout on unmount
70 useEffect(() => {
71 return () => {
72 if (timeoutRef.current) {
73 clearTimeout(timeoutRef.current);
74 }
75 };
76 }, []);
77
78 return {
79 isHovered,
80 ref: ref as React.RefObject<T>,
81 };
82};
83