← Back to all hooks

useHover

Track hover state with pointer events fallback. Supports delays for better UX.

Live Demo

👋

Basic Hover

Hover me

⏱️

Delayed Hover

Wait 500ms

📦

Interactive Card

Hover to see the lift effect

Tooltip Example

📝 Event Log

No hover events yet. Try hovering over the elements!

💡 Try This:

  • Hover over the basic card for instant feedback
  • Try the delayed hover - notice the 500ms wait
  • Hover the interactive card to see lift animation
  • Hover the button to see a tooltip with delay

Code Examples

Basic Hover

import { useHover } from "@uiblock/hooks";

function Card() {
  const [ref, isHovered] = useHover();

  return (
    <div
      ref={ref}
      style={{
        background: isHovered ? 'blue' : 'gray',
        padding: '2rem'
      }}
    >
      {isHovered ? 'Hovering! 🎉' : 'Hover me'}
    </div>
  );
}

With Delays

import { useHover } from "@uiblock/hooks";

function Tooltip() {
  const [ref, isHovered] = useHover({
    delayEnter: 500, // Wait 500ms before showing
    delayLeave: 200  // Wait 200ms before hiding
  });

  return (
    <div>
      <button ref={ref}>Hover for tooltip</button>
      {isHovered && (
        <div className="tooltip">
          This is a tooltip!
        </div>
      )}
    </div>
  );
}

Hover Card with Animation

import { useHover } from "@uiblock/hooks";

function HoverCard() {
  const [ref, isHovered] = useHover({ delayEnter: 100 });

  return (
    <div
      ref={ref}
      style={{
        transform: isHovered ? 'scale(1.05)' : 'scale(1)',
        transition: 'transform 0.2s',
        boxShadow: isHovered 
          ? '0 10px 30px rgba(0,0,0,0.2)' 
          : '0 2px 8px rgba(0,0,0,0.1)'
      }}
    >
      <h3>Card Title</h3>
      <p>Card content</p>
    </div>
  );
}

How It Works

Here's the implementation:

import { useState, useEffect, useRef } from 'react'

export function useHover(options = {}) {
  const { delayEnter = 0, delayLeave = 0, usePointerEvents = true } = options

  const [isHovered, setIsHovered] = useState(false)
  const ref = useRef(null)
  const enterTimeoutRef = useRef()
  const leaveTimeoutRef = useRef()

  useEffect(() => {
    const element = ref.current
    if (!element) return

    const handleEnter = () => {
      // Clear any pending leave timeout
      if (leaveTimeoutRef.current) {
        clearTimeout(leaveTimeoutRef.current)
      }

      if (delayEnter > 0) {
        enterTimeoutRef.current = setTimeout(() => {
          setIsHovered(true)
        }, delayEnter)
      } else {
        setIsHovered(true)
      }
    }

    const handleLeave = () => {
      // Clear any pending enter timeout
      if (enterTimeoutRef.current) {
        clearTimeout(enterTimeoutRef.current)
      }

      if (delayLeave > 0) {
        leaveTimeoutRef.current = setTimeout(() => {
          setIsHovered(false)
        }, delayLeave)
      } else {
        setIsHovered(false)
      }
    }

    // Use pointer events if supported and enabled
    if (usePointerEvents && 'onpointerenter' in element) {
      element.addEventListener('pointerenter', handleEnter)
      element.addEventListener('pointerleave', handleLeave)

      return () => {
        element.removeEventListener('pointerenter', handleEnter)
        element.removeEventListener('pointerleave', handleLeave)
        if (enterTimeoutRef.current) clearTimeout(enterTimeoutRef.current)
        if (leaveTimeoutRef.current) clearTimeout(leaveTimeoutRef.current)
      }
    }

    // Fallback to mouse events
    element.addEventListener('mouseenter', handleEnter)
    element.addEventListener('mouseleave', handleLeave)

    return () => {
      element.removeEventListener('mouseenter', handleEnter)
      element.removeEventListener('mouseleave', handleLeave)
      if (enterTimeoutRef.current) clearTimeout(enterTimeoutRef.current)
      if (leaveTimeoutRef.current) clearTimeout(leaveTimeoutRef.current)
    }
  }, [delayEnter, delayLeave, usePointerEvents])

  return [ref, isHovered]
}

Key Features:

  • Configurable enter and leave delays
  • Pointer events with mouse events fallback
  • Proper timeout cleanup to prevent memory leaks
  • Returns tuple of [ref, isHovered]

API Reference

Options

delayEnter?: number

Delay in ms before hover state becomes true (default: 0)

delayLeave?: number

Delay in ms before hover state becomes false (default: 0)

usePointerEvents?: boolean

Use pointer events for better reliability (default: true)

returns: [RefObject, boolean]

Tuple of [ref to attach, isHovered state]

💡 Use Cases

  • Hover cards and previews
  • Tooltips with delay
  • Interactive buttons
  • Image zoom on hover
  • Navigation menu highlights
  • Product cards in e-commerce