blog-header-image

Custom Hooks: Building an Auto-Hide UI Pattern

Dec 20, 2025

I recently needed a UI element that appears after user interaction and hides itself automatically after a few seconds. Instead of repeating this logic everywhere, I decided to extract it into a custom hook.

Here’s how I approached it.

What problem are we solving?

We want:

  • A UI element that can be shown manually
  • It should auto-hide after a delay
  • Cleanup timers properly
  • Avoid unnecessary re-renders

The Idea

Instead of managing:

  • setTimeout
  • visibility state
  • cleanup logic

inside components, we move everything into a reusable hook.


The Hook

import { useState, useEffect, useRef, useCallback } from "react";

export function useAutoHide(delay = 3000) {
  const [isVisible, setIsVisible] = useState(false);
  const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const hasUserInteracted = useRef(false);

  const show = useCallback(() => {
    setIsVisible(true);

    if (timeoutRef.current) {
      clearTimeout(timeoutRef.current);
    }

    timeoutRef.current = setTimeout(() => {
      setIsVisible(false);
    }, delay);
  }, [delay]);

  const hide = useCallback(() => {
    setIsVisible(false);
    if (timeoutRef.current) {
      clearTimeout(timeoutRef.current);
    }
  }, []);

  useEffect(() => {
    const handleGlobalClick = () => {
      if (!hasUserInteracted.current) {
        show();
        hasUserInteracted.current = true;
      }
    };

    document.addEventListener("click", handleGlobalClick, { once: true });
    return () => document.removeEventListener("click", handleGlobalClick);
  }, [show]);

  useEffect(() => {
    return () => {
      if (timeoutRef.current) clearTimeout(timeoutRef.current);
    };
  }, []);

  return { isVisible, show, hide };
}
Aryan Sharma