npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@qazuor/react-hooks

v1.1.1

Published

A comprehensive collection of production-ready React hooks for modern web applications. Features type-safe implementations, extensive testing, and zero dependencies. Includes hooks for state management, browser APIs, user interactions, and development uti

Readme

Qazuor React Custom Hooks

A collection of high-quality, fully tested React hooks for common use cases. Written in TypeScript with comprehensive documentation and examples.

Table of Contents

Features

  • 📦 20+ Custom Hooks
  • 🔒 Type-safe with TypeScript
  • 📚 Comprehensive documentation
  • ✅ Fully tested
  • 🎯 Zero dependencies
  • 🌳 Tree-shakeable
  • 💻 SSR compatible

Installation

# Using npm
npm install @qazuor/react-hooks

# Using yarn
yarn add @qazuor/react-hooks

# Using pnpm
pnpm add @qazuor/react-hooks

Available Hooks

State Management

useBoolean

Manages a boolean state with convenient methods.

import { useBoolean } from '@qazuor/react-hooks';

function Modal() {
    const { value: isOpen, setTrue: open, setFalse: close } = useBoolean(false);

    return (
        <>
            <button onClick={open} type="button">Open Modal</button>
            {isOpen && (
                <div className="modal">
                    <button onClick={close} type="button">Close</button>
                    <h1>Modal Content</h1>
                </div>
            )}
        </>
    );
}

useToggle

Manages a toggleable boolean state with persistence options.

import { useToggle } from '@qazuor/react-hooks';

function ThemeToggle() {
    const { value: isDark, toggle } = useToggle({
        initialValue: false,
        persist: true,
        storageKey: 'theme-preference'
    });

    return (
        <button onClick={toggle} type="button">
            Current theme: {isDark ? 'Dark' : 'Light'}
        </button>
    );
}

useQueue

Implements a FIFO queue with state management.

import { useQueue } from '@qazuor/react-hooks';

function TaskQueue() {
    const { enqueue, dequeue, peek, size, isEmpty } = useQueue<string>();

    return (
        <div>
            <button onClick={() => enqueue(`Task ${size + 1}`)} type="button">
                Add Task
            </button>
            <button onClick={dequeue} disabled={isEmpty} type="button">
                Process Next
            </button>
            <p>Next task: {peek() || 'No tasks'}</p>
            <p>Queue size: {size}</p>
        </div>
    );
}

Side Effects

useTimeout

Execute a callback after a delay with control methods.

import { useTimeout } from '@qazuor/react-hooks';

function AutoDismiss() {
    const [visible, setVisible] = useState(true);
    const { isPending, reset } = useTimeout({
        callback: () => setVisible(false),
        delay: 3000
    });

    return visible && (
        <div>
            <p>I will disappear in 3 seconds!</p>
            <button onClick={reset} type="button">Reset Timer</button>
        </div>
    );
}

useInterval

Execute a callback at regular intervals with pause/resume functionality.

import { useInterval } from '@qazuor/react-hooks';

function Counter() {
    const [count, setCount] = useState(0);
    const { isRunning, start, pause } = useInterval({
        callback: () => setCount(c => c + 1),
        delay: 1000
    });

    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={isRunning ? pause : start} type="button">
                {isRunning ? 'Pause' : 'Start'}
            </button>
        </div>
    );
}

useHandledInterval

Enhanced interval with random delay options and more control.

import { useHandledInterval } from '@qazuor/react-hooks';

function RandomTimer() {
    const [count, setCount] = useState(0);
    const { isRunning, start, pause, reset } = useHandledInterval({
        callback: () => setCount(c => c + 1),
        delay: 1000,
        random: true,
        minDelay: 500
    });

    return (
        <div>
            <p>Random intervals count: {count}</p>
            <button onClick={isRunning ? pause : start} type="button">
                {isRunning ? 'Pause' : 'Start'}
            </button>
            <button onClick={reset} type="button">Reset</button>
        </div>
    );
}

useDebounce

Debounce a value with configurable delay.

import { useDebounce } from '@qazuor/react-hooks';

function SearchInput() {
    const [value, setValue] = useState('');
    const debouncedValue = useDebounce(value, 500);

    useEffect(() => {
        // API call with debouncedValue
        console.log('Searching:', debouncedValue);
    }, [debouncedValue]);

    return (
        <input
            value={value}
            onChange={(e) => setValue(e.target.value)}
            placeholder="Search..."
        />
    );
}

Browser APIs

useLocalStorage

Persist state in localStorage with type safety.

import { useLocalStorage } from '@qazuor/react-hooks';

function UserPreferences() {
    const [preferences, setPreferences] = useLocalStorage('user-prefs', {
        theme: 'light',
        fontSize: 16
    });

    return (
        <div>
            <button
                onClick={() => setPreferences(p => ({ ...p, theme: p.theme === 'light' ? 'dark' : 'light' }))}
                type="button"
            >
                Toggle Theme
            </button>
            <select
                value={preferences.fontSize}
                onChange={(e) => setPreferences(p => ({ ...p, fontSize: Number(e.target.value) }))}
            >
                <option value="14">Small</option>
                <option value="16">Medium</option>
                <option value="18">Large</option>
            </select>
        </div>
    );
}

useSessionStorage

Persist state in sessionStorage.

import { useSessionStorage } from '@qazuor/react-hooks';

function FormWithAutosave() {
    const [formData, setFormData] = useSessionStorage('form-draft', {
        title: '',
        content: ''
    });

    return (
        <form>
            <input
                value={formData.title}
                onChange={(e) => setFormData(prev => ({ ...prev, title: e.target.value }))}
                placeholder="Title"
            />
            <textarea
                value={formData.content}
                onChange={(e) => setFormData(prev => ({ ...prev, content: e.target.value }))}
                placeholder="Content"
            />
        </form>
    );
}

useCopyToClipboard

Copy text to clipboard with status feedback.

import { useCopyToClipboard } from '@qazuor/react-hooks';

function ShareButton() {
    const { copy, copied, error } = useCopyToClipboard();
    const url = window.location.href;

    return (
        <button
            onClick={() => copy(url)}
            type="button"
            className={copied ? 'success' : error ? 'error' : ''}
        >
            {copied ? 'Copied!' : error ? 'Failed to copy' : 'Copy URL'}
        </button>
    );
}

useMediaQuery

React to media query changes.

import { useMediaQuery } from '@qazuor/react-hooks';

function ResponsiveLayout() {
    const isMobile = useMediaQuery('(max-width: 768px)');
    const prefersDark = useMediaQuery('(prefers-color-scheme: dark)');

    return (
        <div className={`layout ${isMobile ? 'mobile' : 'desktop'} ${prefersDark ? 'dark' : 'light'}`}>
            <p>Current layout: {isMobile ? 'Mobile' : 'Desktop'}</p>
            <p>Theme preference: {prefersDark ? 'Dark' : 'Light'}</p>
        </div>
    );
}

useNetworkState

Track network connectivity status.

import { useNetworkState } from '@qazuor/react-hooks';

function NetworkIndicator() {
    const { online, type, rtt } = useNetworkState();

    return (
        <div>
            <div className={`status-dot ${online ? 'online' : 'offline'}`} />
            {online && (
                <>
                    <p>Connection: {type}</p>
                    <p>Latency: {rtt}ms</p>
                </>
            )}
        </div>
    );
}

useVisibilityChange

Track document visibility state.

import { useVisibilityChange } from '@qazuor/react-hooks';

function VideoPlayer() {
    const videoRef = useRef<HTMLVideoElement>(null);
    const { isVisible } = useVisibilityChange({
        onHidden: () => videoRef.current?.pause(),
        onVisible: () => videoRef.current?.play()
    });

    return (
        <div>
            <video ref={videoRef} />
            <p>Video is {isVisible ? 'visible' : 'hidden'}</p>
        </div>
    );
}

useWindowWidth

Track window width with debouncing.

import { useWindowWidth } from '@qazuor/react-hooks';

function ResponsiveComponent() {
    const { width } = useWindowWidth({
        debounceDelay: 250,
        onChange: (w) => console.log(`Window width changed to ${w}px`)
    });

    return (
        <div>
            <p>Window width: {width}px</p>
            {width > 1024 ? (
                <h1>Desktop View</h1>
            ) : width > 768 ? (
                <h2>Tablet View</h2>
            ) : (
                <h3>Mobile View</h3>
            )}
        </div>
    );
}

User Interaction

useClickOutside

Detect clicks outside an element.

import { useClickOutside } from '@qazuor/react-hooks';

function Dropdown() {
    const [isOpen, setIsOpen] = useState(false);
    const ref = useRef(null);

    useClickOutside(ref, () => setIsOpen(false));

    return (
        <div ref={ref}>
            <button onClick={() => setIsOpen(true)} type="button">
                Toggle Dropdown
            </button>
            {isOpen && (
                <ul className="dropdown-menu">
                    <li>Option 1</li>
                    <li>Option 2</li>
                </ul>
            )}
        </div>
    );
}

useIdleness

Track user idle state.

import { useIdleness } from '@qazuor/react-hooks';

function IdleMonitor() {
    const { isIdle, reset } = useIdleness({
        timeout: 5000,
        onIdleChange: (idle) => {
            if (idle) {
                console.log('User is idle');
            } else {
                console.log('User is active');
            }
        }
    });

    return (
        <div>
            <p>User is currently {isIdle ? 'idle' : 'active'}</p>
            <button onClick={reset} type="button">Reset Idle Timer</button>
        </div>
    );
}

usePageLeave

Detect when user attempts to leave page.

import { usePageLeave } from '@qazuor/react-hooks';

function ExitIntent() {
    const { hasLeft } = usePageLeave({
        onLeave: () => console.log('Mouse left the page'),
        threshold: 10
    });

    return hasLeft && (
        <div className="exit-popup">
            <h2>Wait! Don't leave yet...</h2>
            <p>Would you like to subscribe to our newsletter?</p>
        </div>
    );
}

useLockBodyScroll

Prevent body scrolling.

import { useLockBodyScroll } from '@qazuor/react-hooks';

function Modal({ isOpen }: { isOpen: boolean }) {
    const { isLocked, lock, unlock } = useLockBodyScroll({
        lockImmediately: isOpen,
        preservePosition: true
    });

    useEffect(() => {
        if (isOpen) {
            lock();
        } else {
            unlock();
        }
    }, [isOpen, lock, unlock]);

    return isOpen && (
        <div className="modal">
            <h2>Modal Content</h2>
            <p>Body scroll is {isLocked ? 'locked' : 'unlocked'}</p>
        </div>
    );
}

useMeasure

Measure DOM elements.

import { useMeasure } from '@qazuor/react-hooks';

function ResizableBox() {
    const { ref, size } = useMeasure();

    return (
        <div
            ref={ref}
            style={{
                resize: 'both',
                overflow: 'auto',
                minWidth: '100px',
                minHeight: '100px',
                border: '1px solid black'
            }}
        >
            <p>Width: {size.width}px</p>
            <p>Height: {size.height}px</p>
        </div>
    );
}

Development

useLogger

Debug values with console logging.

import { useLogger } from '@qazuor/react-hooks';

function DebugComponent() {
    const [count, setCount] = useState(0);

    useLogger('Counter Value', count, {
        level: 'info',
        timestamp: true,
        formatter: (label, value) => `${label}: ${value} (${new Date().toISOString()})`
    });

    return (
        <button onClick={() => setCount(c => c + 1)} type="button">
            Increment ({count})
        </button>
    );
}

TypeScript Support

All hooks are written in TypeScript and include comprehensive type definitions. Generic types are used where appropriate to ensure type safety.

interface UserPreferences {
    theme: 'light' | 'dark';
    fontSize: number;
}

// Type-safe localStorage hook
const [preferences, setPreferences] = useLocalStorage<UserPreferences>('prefs', {
    theme: 'light',
    fontSize: 16
});

// TypeScript knows the correct types
preferences.theme; // 'light' | 'dark'
preferences.fontSize; // number

Browser Support

The library supports all modern browsers. Some hooks may require specific browser features - check individual hook documentation for details.

Contributing

Contributions are welcome! Please read our Contributing Guide for details on our code of conduct and the process for submitting pull requests.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Author

Leandro Asrilevich (@qazuor)