Tracks user activity and determines when the user has become idle. Uses throttled event handlers for performance.
Installation
npm install betteruseUsage
import { useIdle } from 'betteruse'
function IdleWarning() {
const { isIdle, lastActive } = useIdle({
timeout: 60000, // 1 minute
onIdle: () => console.log('User is idle'),
onActive: () => console.log('User is active'),
})
return (
<div>
{isIdle ? (
<p>Are you still there?</p>
) : (
<p>Last active: {new Date(lastActive).toLocaleTimeString()}</p>
)}
</div>
)
}
API Reference
useIdle(options)
| Prop | Type | Default | Description |
|---|---|---|---|
timeout | number | 60000 | Timeout in milliseconds before considered idle |
events | string[] | ['mousemove', 'keydown', 'touchstart', 'scroll', 'mousedown', 'wheel'] | Events to track for activity |
enabled | boolean | true | Whether the hook is enabled |
onIdle | () => void | - | Callback when user becomes idle |
onActive | () => void | - | Callback when user becomes active again |
Return Value
| Prop | Type | Default | Description |
|---|---|---|---|
isIdle | boolean | - | Whether the user is currently idle |
lastActive | number | - | Timestamp of last activity |
reset | () => void | - | Reset the idle timer |
How It Works
- The hook listens to configured activity events (mouse, keyboard, touch, scroll)
- Event handlers are throttled (500ms) for performance
- A timeout is set after each activity
- When timeout expires without activity,
isIdlebecomestrue - Any new activity resets the timer and
isIdle
This hook is SSR-safe. Event listeners are only added on the client.
Examples
Session Timeout Warning
function SessionWarning() {
const [showWarning, setShowWarning] = useState(false)
const { isIdle, reset } = useIdle({
timeout: 5 * 60 * 1000, // 5 minutes
onIdle: () => setShowWarning(true),
onActive: () => setShowWarning(false),
})
const extendSession = () => {
reset()
setShowWarning(false)
// Optionally refresh auth token
}
if (!showWarning) return null
return (
<div className="fixed bottom-4 right-4 p-4 bg-yellow-100 rounded">
<p>Your session will expire soon due to inactivity.</p>
<button onClick={extendSession}>Stay Logged In</button>
</div>
)
}
Auto-pause Video
function AutoPauseVideo({ src }: { src: string }) {
const videoRef = useRef<HTMLVideoElement>(null)
useIdle({
timeout: 30000, // 30 seconds
onIdle: () => {
videoRef.current?.pause()
},
})
return <video ref={videoRef} src={src} controls />
}
Activity Dashboard
function ActivityStatus() {
const { isIdle, lastActive } = useIdle({
timeout: 60000,
})
const timeAgo = useMemo(() => {
const seconds = Math.floor((Date.now() - lastActive) / 1000)
if (seconds < 60) return `${seconds}s ago`
return `${Math.floor(seconds / 60)}m ago`
}, [lastActive])
return (
<div className="flex items-center gap-2">
<div
className={`w-2 h-2 rounded-full ${
isIdle ? 'bg-yellow-500' : 'bg-green-500'
}`}
/>
<span>{isIdle ? 'Away' : 'Active'}</span>
<span className="text-muted">{timeAgo}</span>
</div>
)
}
Custom Events
function CustomIdleDetection() {
const { isIdle } = useIdle({
timeout: 30000,
// Only track specific events
events: ['click', 'keydown'],
})
return <div>{isIdle ? 'Click or type to continue' : 'Active'}</div>
}
Performance
Event handlers are throttled to 500ms to prevent excessive state updates. This means:
- Activities within 500ms of each other are grouped
- The timeout resets on the first activity in each 500ms window
- Battery and CPU usage is minimized