Skip to content

geon0529/usefy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

usefy logo

usefy

πŸͺ A collection of production-ready React hooks for modern applications

npm version npm downloads bundle size license

Installation β€’ Packages β€’ Quick Start β€’ Features


⚠️ Pre-release Notice: This project is currently in version 0.x.x (alpha/beta stage). APIs may change between minor versions. While fully functional and tested, please use with caution in production environments.

🚧 Actively Developing: New hooks are being added regularly. Stay tuned for more utilities!


Overview

usefy is a collection of production-ready custom hooks designed for modern React applications. All hooks are written in TypeScript, providing complete type safety, comprehensive testing, and minimal bundle size.

✨ Why usefy?

  • πŸš€ Zero Dependencies β€” Pure React implementation with no external dependencies
  • πŸ“¦ Tree Shakeable β€” Import only the hooks you need to optimize bundle size
  • πŸ”· TypeScript First β€” Complete type safety with full autocomplete support
  • ⚑ SSR Compatible β€” Works seamlessly with Next.js, Remix, and other SSR frameworks
  • πŸ§ͺ Well Tested β€” High test coverage ensures reliability and stability
  • πŸ“– Well Documented β€” Detailed documentation with practical examples

Installation

All-in-One Package

Install all hooks at once:

# npm
npm install @usefy/usefy

# yarn
yarn add @usefy/usefy

# pnpm
pnpm add @usefy/usefy

Individual Packages

You can also install only the hooks you need:

# Example: Install only use-toggle
pnpm add @usefy/use-toggle

# Install multiple packages
pnpm add @usefy/use-debounce @usefy/use-local-storage

Peer Dependencies

All packages require React 18 or 19:

{
  "peerDependencies": {
    "react": "^18.0.0 || ^19.0.0"
  }
}

Packages

πŸ“¦ Available Hooks

Hook Description npm Coverage
@usefy/use-toggle Boolean state management with toggle, setTrue, setFalse npm 100%
@usefy/use-counter Counter state with increment, decrement, reset npm 100%
@usefy/use-debounce Value debouncing with leading/trailing edge npm 91%
@usefy/use-debounce-callback Debounced callbacks with cancel/flush/pending npm 94%
@usefy/use-throttle Value throttling for rate-limiting updates npm 100%
@usefy/use-throttle-callback Throttled callbacks with cancel/flush/pending npm 100%
@usefy/use-local-storage localStorage persistence with cross-tab sync npm 95%
@usefy/use-session-storage sessionStorage persistence for tab lifetime npm 94%
@usefy/use-click-any-where Document-wide click event detection npm 92%
@usefy/use-copy-to-clipboard Clipboard copy with fallback support npm 88%
@usefy/use-event-listener DOM event listener with auto cleanup npm 96%
@usefy/use-on-click-outside Outside click detection for modals/dropdowns npm 97%
@usefy/use-timer Countdown timer with drift compensation and formats npm 84%

Quick Start

Using the All-in-One Package

import {
  useToggle,
  useCounter,
  useDebounce,
  useLocalStorage,
  useCopyToClipboard,
  useEventListener,
  useOnClickOutside,
} from "@usefy/usefy";

function App() {
  // Boolean state management
  const { value: isOpen, toggle, setFalse: close } = useToggle(false);

  // Counter with controls
  const { count, increment, decrement, reset } = useCounter(0);

  // Debounced search
  const [query, setQuery] = useState("");
  const debouncedQuery = useDebounce(query, 300);

  // Persistent theme preference
  const [theme, setTheme] = useLocalStorage("theme", "light");

  // Copy functionality
  const [copiedText, copy] = useCopyToClipboard();

  return (
    <div data-theme={theme}>
      {/* Modal */}
      <button onClick={toggle}>Open Modal</button>
      {isOpen && (
        <div className="modal">
          <button onClick={close}>Close</button>
        </div>
      )}

      {/* Counter */}
      <div>
        <button onClick={decrement}>-</button>
        <span>{count}</span>
        <button onClick={increment}>+</button>
      </div>

      {/* Search */}
      <input
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="Search..."
      />

      {/* Theme Toggle */}
      <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
        Toggle Theme
      </button>

      {/* Copy */}
      <button onClick={() => copy("Hello World!")}>
        {copiedText ? "Copied!" : "Copy"}
      </button>
    </div>
  );
}

Using Individual Packages

import { useToggle } from "@usefy/use-toggle";
import { useDebounce } from "@usefy/use-debounce";

function SearchModal() {
  const { value: isOpen, toggle } = useToggle(false);
  const [query, setQuery] = useState("");
  const debouncedQuery = useDebounce(query, 300);

  useEffect(() => {
    if (debouncedQuery) {
      searchAPI(debouncedQuery);
    }
  }, [debouncedQuery]);

  return (
    <>
      <button onClick={toggle}>Search</button>
      {isOpen && (
        <input value={query} onChange={(e) => setQuery(e.target.value)} />
      )}
    </>
  );
}

Features

πŸ”„ State Management

useToggle β€” Boolean state with utility functions
const { value, toggle, setTrue, setFalse, setValue } = useToggle(false);

Perfect for modals, dropdowns, accordions, and switches.

useCounter β€” Counter state with controls
const { count, increment, decrement, reset } = useCounter(0);

Ideal for quantity selectors, pagination, and score tracking.

⏱️ Timing Utilities

useDebounce β€” Debounce value updates
const debouncedValue = useDebounce(value, 300, {
  leading: false,
  trailing: true,
  maxWait: 1000,
});

Best for search inputs, form validation, and API calls.

useDebounceCallback β€” Debounce function calls
const debouncedFn = useDebounceCallback(callback, 300);

debouncedFn(args); // Call debounced
debouncedFn.cancel(); // Cancel pending
debouncedFn.flush(); // Execute immediately
debouncedFn.pending(); // Check if pending
useThrottle β€” Throttle value updates
const throttledValue = useThrottle(value, 100, {
  leading: true,
  trailing: true,
});

Perfect for scroll events, resize handlers, and mouse tracking.

useThrottleCallback β€” Throttle function calls
const throttledFn = useThrottleCallback(callback, 100);
useTimer β€” Countdown timer with accurate timing
import { useTimer, ms } from "@usefy/use-timer";

const timer = useTimer(ms.minutes(5), {
  format: "MM:SS",
  autoStart: false,
  loop: false,
  onComplete: () => console.log("Time's up!"),
});

// Controls
timer.start();
timer.pause();
timer.reset();
timer.addTime(ms.seconds(10));
timer.subtractTime(ms.seconds(5));

// State
timer.formattedTime; // "05:00"
timer.progress; // 0-100
timer.isRunning; // boolean

Perfect for countdown timers, Pomodoro apps, kitchen timers, and time-based UIs with smart render optimization.

πŸ’Ύ Storage

useLocalStorage β€” Persistent storage with sync
const [value, setValue, removeValue] = useLocalStorage("key", initialValue, {
  serializer: JSON.stringify,
  deserializer: JSON.parse,
  syncTabs: true,
  onError: (error) => console.error(error),
});

Supports cross-tab synchronization and custom serialization.

useSessionStorage β€” Session-scoped storage
const [value, setValue, removeValue] = useSessionStorage("key", initialValue);

Data persists during tab lifetime, isolated per tab.

πŸ–±οΈ Events

useEventListener β€” DOM event listener with auto cleanup
// Window resize event (default target)
useEventListener("resize", (e) => {
  console.log("Window resized:", window.innerWidth);
});

// Document keydown event
useEventListener(
  "keydown",
  (e) => {
    if (e.key === "Escape") closeModal();
  },
  document
);

// Element with ref
const buttonRef = useRef<HTMLButtonElement>(null);
useEventListener("click", handleClick, buttonRef);

// With options
useEventListener("scroll", handleScroll, window, {
  passive: true,
  capture: false,
  enabled: isTracking,
});

Supports window, document, HTMLElement, and RefObject targets with full TypeScript type inference.

useOnClickOutside β€” Outside click detection
// Basic usage - close modal on outside click
const modalRef = useRef<HTMLDivElement>(null);
useOnClickOutside(modalRef, () => onClose(), { enabled: isOpen });

// Multiple refs - button and dropdown menu
const buttonRef = useRef<HTMLButtonElement>(null);
const menuRef = useRef<HTMLDivElement>(null);
useOnClickOutside([buttonRef, menuRef], () => setIsOpen(false), {
  enabled: isOpen,
});

// With exclude refs
useOnClickOutside(modalRef, onClose, {
  excludeRefs: [toastRef], // Clicks on toast won't close modal
});

Perfect for modals, dropdowns, popovers, tooltips, and context menus with mouse + touch support.

useClickAnyWhere β€” Global click detection
useClickAnyWhere(
  (event) => {
    if (!ref.current?.contains(event.target)) {
      closeMenu();
    }
  },
  { enabled: isOpen }
);

Ideal for closing dropdowns, modals, and context menus.

useCopyToClipboard β€” Clipboard operations
const [copiedText, copy] = useCopyToClipboard({
  timeout: 2000,
  onSuccess: (text) => toast.success("Copied!"),
  onError: (error) => toast.error("Failed to copy"),
});

const success = await copy("text to copy");

Modern Clipboard API with automatic fallback for older browsers.


Test Coverage

All packages are comprehensively tested using Vitest to ensure reliability and stability.

Package Statements Branches Functions Lines
use-toggle 100% 100% 100% 100%
use-counter 100% 100% 100% 100%
use-throttle 100% 100% 100% 100%
use-throttle-callback 100% 100% 100% 100%
use-local-storage 95% 86% 100% 95%
use-session-storage 94% 79% 100% 94%
use-debounce-callback 94% 83% 94% 94%
use-click-any-where 92% 88% 100% 92%
use-debounce 91% 90% 67% 93%
use-copy-to-clipboard 88% 79% 86% 88%
use-event-listener 96% 91% 100% 96%
use-on-click-outside 97% 93% 100% 97%
use-timer 84% 73% 94% 84%

Browser Support

Browser Version
Chrome 66+
Firefox 63+
Safari 13.1+
Edge 79+
IE 11 Fallback support

Related Links


License

MIT Β© mirunamu


Built with ❀️ by the usefy team

GitHub stars

About

A collection of useful React hooks for modern web development

Resources

Contributing

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •  

Languages