Skip to main content

All hooks

useIdle

Custom hook that tracks whether the user is idle (no activity for a specified time).


Pass a timeout in milliseconds. Returns:

  • idle — whether the user has been inactive for the specified duration
  • lastActive — timestamp of the last detected activity

Listens for mousemove, mousedown, keydown, touchstart, and scroll events. Useful for session timeouts, auto-save, or activity indicators.

Usage

import { useIdle } from '@ts-hooks-kit/core'

function Example() {
  const result = useIdle()
  return <pre>{JSON.stringify(result, null, 2)}</pre>
}

API

function useIdle(timeout: number, options?: UseIdleOptions): IdleState

Custom hook that tracks whether the user is idle (no activity for a specified time).

Parameters

NameTypeDefault valueDescription
timeoutnumber-The time in milliseconds of inactivity before considering the user idle.
options?UseIdleOptions{}Options for customizing the hook behavior.

Returns

The current idle state and last activity timestamp.

Type declaration

IdleState

Represents the state returned by useIdle hook.

NameTypeDescription
idlebooleanWhether the user is currently idle.
lastActivenumberThe timestamp of the last user activity.

UseIdleOptions

Options for the useIdle hook.

NameTypeDescription
eventsunknown[]Events that should reset the idle timer.
initialIdlebooleanWhether to start in idle state.

Hook

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

/**
 * Options for the useIdle hook.
 */
export type UseIdleOptions = {
  /** Events that should reset the idle timer. */
  events?: (keyof WindowEventMap)[]
  /** Whether to start in idle state. */
  initialIdle?: boolean
}

/**
 * Represents the state returned by useIdle hook.
 */
export type IdleState = {
  /** Whether the user is currently idle. */
  idle: boolean
  /** The timestamp of the last user activity. */
  lastActive: number
}

/**
 * Default events that indicate user activity.
 */
const DEFAULT_EVENTS: (keyof WindowEventMap)[] = [
  'mousemove',
  'mousedown',
  'resize',
  'keydown',
  'touchstart',
  'wheel',
]

/**
 * Custom hook that tracks whether the user is idle (no activity for a specified time).
 * @param {number} timeout - The time in milliseconds of inactivity before considering the user idle.
 * @param {UseIdleOptions} [options] - Options for customizing the hook behavior.
 * @returns {IdleState} The current idle state and last activity timestamp.
 * @public
 * @see [Documentation](https://usehooks-ts.com/react-hook/use-idle)
 * @example
 * ```tsx
 * const { idle, lastActive } = useIdle(5000);
 *
 * return (
 *   <div>
 *     <p>{idle ? 'User is idle' : 'User is active'}</p>
 *     <p>Last active: {new Date(lastActive).toLocaleString()}</p>
 *   </div>
 * );
 * ```
 */
export function useIdle(
  timeout: number,
  options: UseIdleOptions = {},
): IdleState {
  const { events = DEFAULT_EVENTS, initialIdle = false } = options

  const [state, setState] = useState<IdleState>({
    idle: initialIdle,
    lastActive: Date.now(),
  })

  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null)

  useEffect(() => {
    const resetIdle = () => {
      if (timerRef.current) {
        clearTimeout(timerRef.current)
      }

      setState({
        idle: false,
        lastActive: Date.now(),
      })

      timerRef.current = setTimeout(() => {
        setState(prev => ({ ...prev, idle: true }))
      }, timeout)
    }

    events.forEach(event => {
      window.addEventListener(event, resetIdle)
    })

    // Initial timer
    timerRef.current = setTimeout(() => {
      setState(prev => ({ ...prev, idle: true }))
    }, timeout)

    return () => {
      events.forEach(event => {
        window.removeEventListener(event, resetIdle)
      })
      if (timerRef.current) {
        clearTimeout(timerRef.current)
      }
    }
  }, [timeout, events])

  return state
}