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 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-additional-hooks

v0.2.3

Published

Collection of additional React hooks for React and Next.js applications

Readme

react-additional-hooks

npm version License: MIT

A collection of useful and reusable React hooks for everyday development. Supports TypeScript, SSR, and optimized for performance.

📦 Installation

npm install react-additional-hooks
# or
yarn add react-additional-hooks
# or
pnpm add react-additional-hooks

🎯 Features

  • TypeScript — full type definitions included
  • SSR-ready — safe server-side rendering
  • Zero dependencies — only react in peer dependencies
  • Tree-shakeable — import only what you need
  • Well tested — each hook is covered by tests

🚀 Quick Start

import {
  useToggle,
  useDebounce,
  useLocalStorage,
} from "react-additional-hooks";

function MyComponent() {
  const [isOpen, toggle] = useToggle(false);
  const [search, setSearch] = useState("");
  const debouncedSearch = useDebounce(search, 500);
  const [theme, setTheme] = useLocalStorage("theme", "light");

  return (
    <div>
      <button onClick={toggle}>{isOpen ? "Close" : "Open"}</button>
      <input
        onChange={(e) => setSearch(e.target.value)}
        placeholder="Search..."
      />
      <p>Searching for: {debouncedSearch}</p>
    </div>
  );
}

📖 API

State Hooks

useToggle

Manages boolean state with convenient methods.

const [isOpen, toggle, open, close, set] = useToggle(initialState?: boolean);

// Example
const [isModalOpen, toggleModal, openModal, closeModal] = useToggle(false);

useCounter

Counter with constraints and step support.

const { count, increment, decrement, reset, set } = useCounter(
  initialValue?: number,
  options?: { min?: number; max?: number; step?: number }
);

// Example
const { count, increment, decrement } = useCounter(0, { min: 0, max: 10, step: 2 });

Storage Hooks

useLocalStorage

Sync state with localStorage.

const [value, setValue] = useLocalStorage<T>(key: string, initialValue: T);

// Example
const [user, setUser] = useLocalStorage<User>('user', { name: 'John', age: 30 });

useSessionStorage

Sync state with sessionStorage.

const [value, setValue] = useSessionStorage<T>(key: string, initialValue: T);

Optimization Hooks

useDebounce

Debounce a value.

const debouncedValue = useDebounce<T>(value: T, delay: number);

// Example: search with delay
const [searchTerm, setSearchTerm] = useState('');
const debouncedSearch = useDebounce(searchTerm, 500);

useThrottle

Throttle a value.

const throttledValue = useThrottle<T>(value: T, limit: number);

// Example: scroll tracking
const [scrollY, setScrollY] = useState(0);
const throttledScroll = useThrottle(scrollY, 100);

Timer Hooks

useInterval

Interval with automatic cleanup.

useInterval(callback: () => void, delay: number | null);

// Example: timer
const [seconds, setSeconds] = useState(0);
useInterval(() => setSeconds(s => s + 1), 1000);

useTimeout

Timeout with automatic cleanup.

useTimeout(callback: () => void, delay: number | null);

// Example: hide notification after 3 seconds
useTimeout(() => setShowNotification(false), 3000);

DOM Hooks

useClickOutside

Detect clicks outside an element.

const ref = useClickOutside<T>(handler: () => void);

// Example: close modal when clicking outside
const modalRef = useClickOutside(() => setIsOpen(false));
return <div ref={modalRef}>Modal content</div>;

useHover

Track mouse hover state.

const [ref, isHovered] = useHover<T>();

// Example
const [hoverRef, isHovered] = useHover();
return <div ref={hoverRef}>{isHovered ? "Hovering!" : "Not hovering"}</div>;

useKeyPress

Track key presses.

const isPressed = useKeyPress(targetKey: string | string[]);

// Example
const isEscapePressed = useKeyPress('Escape');
const isCtrlCPressed = useKeyPress(['Control', 'c']);

useMediaQuery

Track CSS media query matches.

const matches = useMediaQuery(query: string);

// Example
const isMobile = useMediaQuery('(max-width: 768px)');
const isDarkMode = useMediaQuery('(prefers-color-scheme: dark)');

Responsive Design

useBreakpoint

Powerful hook for tracking breakpoints.

const breakpoints = { sm: 640, md: 768, lg: 1024 };
const { sm, md, lg, width } = useBreakpoint(breakpoints, options?: UseBreakpointOptions);

// Example
function ResponsiveComponent() {
  const { sm, md, lg } = useBreakpoint({ sm: 640, md: 768, lg: 1024 });

  return (
    <>
      {sm && <MobileView />}
      {md && <TableView />}
      {lg && <DesktopView />}
    </>
  );
}

useTailwindBreakpoint

Pre-configured Tailwind CSS breakpoints.

const { sm, md, lg, xl, '2xl': xxl, width } = useTailwindBreakpoint(options?: UseBreakpointOptions);

BreakpointProvider & useBreakpointContext

Context provider for performance optimization in deep component trees.

// Root component
<BreakpointProvider breakpoints={breakpoints}>
  <App />
</BreakpointProvider>;

// Deep component
const { sm, md } = useBreakpointContext();

Clipboard Hook

useCopyToClipboard

Copy text to clipboard.

const [copiedText, copy] = useCopyToClipboard();

// Example
const [copied, copy] = useCopyToClipboard();
return <button onClick={() => copy("Text to copy")}>Copy</button>;

Utility Hooks

usePrevious

Get the previous value.

const prevValue = usePrevious<T>(value: T);

// Example
const [count, setCount] = useState(0);
const prevCount = usePrevious(count);

Utility Hooks

usePrevious

Get the previous value.

useTheme

Multi-theme management with localStorage and system preference support.

const { theme, themes, setTheme, isTheme, systemTheme } = useTheme({
  themes: ["light", "dark", "blue", "forest"] as const,
  defaultTheme: "light",
  storageKey: "app-theme",
  themeClassName: "theme",
  dataAttribute: "data-theme",
  onThemeChange: (newTheme) => console.log("Theme changed:", newTheme),
});

// Example
function ThemeSwitcher() {
  const { theme, themes, setTheme, isTheme } = useTheme({
    themes: ["light", "dark", "ocean", "sunset"],
    defaultTheme: "light",
  });

  return (
    <div className={`app theme-${theme}`}>
      {themes.map((t) => (
        <button
          key={t}
          onClick={() => setTheme(t)}
          className={isTheme(t) ? "active" : ""}
        >
          {t}
        </button>
      ))}
      <p>Current theme: {theme}</p>
    </div>
  );
}

Options:

| Option | Type | Required | Description | | ---------------- | ------------------------- | -------- | ------------------------------------------------- | | themes | readonly string[] | ✅ | List of available themes | | defaultTheme | string | ✅ | Default theme (must be in themes) | | storageKey | string | ❌ | localStorage key (default: 'theme') | | useSystemTheme | boolean | ❌ | Use system preference as fallback (default: true) | | themeClassName | string | ❌ | CSS class prefix (adds {prefix}-{theme}) | | dataAttribute | string | ❌ | Data attribute name | | onThemeChange | (theme: string) => void | ❌ | Callback when theme changes |

Returns:

| Property | Type | Description | | ------------- | ---------------------------- | ------------------------ | | theme | string | Current active theme | | themes | readonly string[] | List of available themes | | setTheme | (theme: string) => void | Set current theme | | isTheme | (theme: string) => boolean | Check if theme is active | | systemTheme | 'light' \| 'dark' \| null | System preference |

CSS Setup:

.theme-light {
  --bg: #ffffff;
  --text: #000000;
}
.theme-dark {
  --bg: #1a1a1a;
  --text: #ffffff;
}
.theme-blue {
  --bg: #e8f4f8;
  --text: #003366;
}

body {
  background-color: var(--bg);
  color: var(--text);
}

Hook for managing multiple themes (light, dark, custom themes) with localStorage and system preference support.

const { theme, themes, setTheme, isTheme, systemTheme } = useTheme({
  themes: ['light', 'dark', 'blue', 'forest'] as const,
  defaultTheme: 'light',
  storageKey: 'app-theme',
  themeClassName: 'theme',      // adds class 'theme-dark', 'theme-blue', etc.
  dataAttribute: 'data-theme',  // adds data-theme="dark"
  onThemeChange: (newTheme) => console.log('Theme changed:', newTheme),
});

// Example
function ThemeSwitcher() {
  const { theme, themes, setTheme, isTheme } = useTheme({
    themes: ['light', 'dark', 'ocean', 'sunset'],
    defaultTheme: 'light',
  });

  return (
    <div className={`app theme-${theme}`}>
      {themes.map(t => (
        <button
          key={t}
          onClick={() => setTheme(t)}
          className={isTheme(t) ? 'active' : ''}
        >
          {t}
        </button>
      ))}
      <p>Current theme: {theme}</p>
    </div>
  );
}

## 📦 Swiper Integration

The `useSwiperCustom` hook requires `swiper` to be installed separately:

```bash
npm install swiper
import { useSwiperCustom } from "react-additional-hooks/swiper";
import { Swiper, SwiperSlide } from "swiper/react";
import "swiper/css";

function MySlider() {
  const { swiperInitHandler, activeSlideIndex, nextSlideHandler } =
    useSwiperCustom();

  return (
    <>
      <Swiper onSwiper={swiperInitHandler}>
        <SwiperSlide>Slide 1</SwiperSlide>
        <SwiperSlide>Slide 2</SwiperSlide>
      </Swiper>
      <button onClick={nextSlideHandler}>Next: {activeSlideIndex}</button>
    </>
  );
}

💡 Performance Tips

1. Use useBreakpointContext for deep component trees

// ❌ Bad - each component creates its own handler
function Parent() {
  const { md } = useTailwindBreakpoint();
  return <Child />;
}

// ✅ Good - single handler for all
function Parent() {
  return (
    <BreakpointProvider breakpoints={tailwindBreakpoints}>
      <Child />
    </BreakpointProvider>
  );
}

2. Debounce expensive operations

const debouncedSearch = useDebounce(searchTerm, 500);

useEffect(() => {
  // API call only after typing pauses
  fetchResults(debouncedSearch);
}, [debouncedSearch]);

3. Lazy load Swiper hooks

// Instead of direct import
import { useSwiperCustom } from "react-additional-hooks/swiper";

// Use dynamic import if Swiper isn't always needed
const { useSwiperCustom } = await import("react-additional-hooks/swiper");

🐛 Debugging

All hooks work with React DevTools out of the box. For custom debugging:

function DebugComponent() {
  const { width } = useTailwindBreakpoint();

  useEffect(() => {
    console.log(`Window width changed to ${width}px`);
  }, [width]);

  return null;
}

🔧 Requirements

  • React 16.8.0 or higher
  • (Optional) Swiper 8.0.0 or higher for useSwiperCustom

📄 License

MIT

🤝 Contributing

PRs are welcome! Please ensure:

  1. Code is covered by tests
  2. TypeScript types are included
  3. Documentation is updated
  4. All linter checks pass

📚 Useful Links


⭐ Star the GitHub repository if you find this project useful!