A collection of essential hooks designed for both React and Voby environments. This library provides a comprehensive set of utility hooks that help you build better applications with less code, featuring dual builds optimized for both browser and server-side rendering (SSR) environments.
- 🎯 50+ Essential Hooks - State management, effects, events, utilities
- ⚡ Dual Builds - Optimized bundles for browser (37KB) and SSR (15KB)
- 🔒 Type Safe - Full TypeScript support with separate type definitions
- 🌐 Universal Compatibility - Works with React 16.8+ and Voby
- 📦 Tree Shakeable - Only import what you need
# Using npm
npm install @woby/use
# Using yarn
yarn add @woby/use
# Using pnpm
pnpm add @woby/useThe library provides separate builds for browser and server-side rendering (SSR) environments:
// Default import - works in both environments (uses SSR-safe hooks only)
import { useCounter, useBoolean } from '@woby/use';
// Explicit browser import - includes ALL hooks (browser + SSR-safe)
import { useLocalStorage, useEventListener } from '@woby/use/browser';
// Explicit SSR import - only SSR-compatible hooks
import { useCounter, useDebounce } from '@woby/use/ssr';| Import Path | Use Case | Bundle Size | Hooks Included |
|---|---|---|---|
@woby/use (default) |
Universal/isomorphic components | 15 KB | SSR-safe only (29 hooks) |
@woby/use/browser |
Client-only features | 37 KB | ALL hooks (60+ hooks) |
@woby/use/ssr |
Server-side rendering | 15 KB | SSR-safe only (29 hooks) |
Recommendation: Start with the default import. Only use /browser when you specifically need browser-only hooks like useLocalStorage or useEventListener.
The library is split into two builds to optimize for different environments:
These hooks work perfectly in SSR environments and don't require browser APIs:
State Management:
useBoolean,useCounter,useMap,useSet,useStep,useToggle,useInvert,useDestruct
Timers & Effects:
useDebounce,useTimeout,useInterval,useTimer,usePause
Callbacks & Refs:
useEventCallback,useIsomorphicLayoutEffect,useId,useWith
Utilities:
useTry,useSsr,Array,Object,Ratio,use
These hooks require browser APIs (window, document, navigator, etc.) and should NOT be used during SSR:
Storage:
useLocalStorage,useSessionStorage
DOM Events:
useEventListener,useClickAway,useClickAnyWhere,useOnClickOutside,useHover
Layout & Size:
useElementSize,useWindowSize,useViewportSize,useAspect,useComputedStyle
Location & Screen:
useLocation,useGpsLocation,useScreen,useScreenOrientation,useMediaQuery
Observers:
useIntersectionObserver
Document Operations:
useDocumentTitle,useLockedBody
Browser APIs:
useCopyToClipboard,useScript,useImageOnLoad,useFetch,useSelection
Theme:
useDarkMode,useTernaryDarkMode
Other:
isLocalhost
// This works in both browser and server - perfect for Next.js pages, Nuxt components, etc.
import { useCounter, useDebounce } from '@woby/use';
function Counter() {
const { count, increment } = useCounter(0);
const debouncedCount = useDebounce(count, 300);
return <div>{debouncedCount}</div>;
}// Only import browser hooks in client components
'use client'; // If using Next.js app router
import { useLocalStorage, useEventListener } from '@woby/use/browser';
function StorageComponent() {
const value = useLocalStorage('key', 'default');
return <div>{value}</div>;
}// Universal component (SSR-safe)
import { useCounter } from '@woby/use';
export function Counter() {
const { count } = useCounter(0);
return <div>{count}</div>;
}
// Client component (with browser hooks)
'use client';
import { useLocalStorage } from '@woby/use/browser';
export function PersistentCounter() {
const [value, setValue] = useLocalStorage('counter', 0);
return <div>{value}</div>;
}Next.js App Router:
// Server Component (default)
import { useCounter } from '@woby/use'; // ✅ Works fine
// Client Component
'use client';
import { useLocalStorage } from '@woby/use/browser'; // ✅ Has browser APIsNuxt 3:
<script setup>
// Auto-imported in templates, but explicit imports needed for composables
import { useCounter } from '@woby/use'
import { useLocalStorage } from '@woby/use/browser'
</script>React SPA (No SSR):
// You can safely import everything from browser build
import { useLocalStorage, useEventListener } from '@woby/use/browser';import { useToggle, useCounter, useLocalStorage } from '@woby/use/browser';
function MyComponent() {
const [value, toggle] = useToggle(false);
const { count, increment, decrement } = useCounter(0);
const [name, setName] = useLocalStorage('name', '');
return (
<div>
<p>Toggle value: {() => $(value) ? 'ON' : 'OFF'}</p>
<button onClick={toggle}>Toggle</button>
<p>Count: {count}</p>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Enter your name"
/>
</div>
);
}Note: The example above uses
@woby/use/browserbecause it includesuseLocalStorage. For SSR-safe components, use the default import and avoid browser-only hooks.
use- Convert values to observables with optional cloning
useBoolean- Tracks state of a boolean valueuseCounter- Tracks numerical state with increment/decrement functionsuseToggle- Toggles between two valuesuseMap- Tracks state of a MapuseSet- Tracks state of a SetuseStep- Manages step navigationuseCountdown- Manages countdown timers
useLocalStorage- Manages localStorage valuesuseSessionStorage- Manages sessionStorage valuesuseReadLocalStorage- Reads localStorage valuesuseWindowSize- Tracks window size changesuseAspect- Calculates window aspect ratiouseViewportSize- Accesses visual viewport propertiesuseDarkMode- Tracks and toggles dark mode stateuseTernaryDarkMode- Advanced dark mode managementuseMediaQuery- Tracks media query matchesuseCopyToClipboard- Copies text to clipboarduseDocumentTitle- Sets the document titleuseLockedBody- Locks body scrollinguseElementSize- Tracks element sizeuseIntersectionObserver- Observes element intersectionsuseImageOnLoad- Handles image loadinguseScreen- Accesses screen informationuseGpsLocation- Accesses GPS locationuseLocation- Accesses browser locationuseScreenOrientation- Accesses screen orientationuseSelection- Accesses text selection
useEventListener- Subscribes to eventsuseClickAnyWhere- Subscribes a callback to clicks anywhere on the pageuseClickAway- Detects clicks outside an elementuseOnClickOutside- Detects clicks outside an element
useDebounce- Debounces a value or functionuseTimeout- Sets up a timeout that runs a callbackuseInterval- Sets up an interval that runs a callbackuseIsomorphicLayoutEffect- useLayoutEffect in browser, useEffect in serveruseEffectOnce- Runs an effect only onceuseUpdateEffect- Runs an effect on updates only
useFetch- Fetches data from a URLuseScript- Loads external scriptsuseHover- Tracks hover state of an elementuseDestruct- Destructures objects and arraysuseEventCallback- Creates stable event callbacksuseId- Generates unique IDsuseInvert- Inverts boolean valuesusePause- Creates timed delaysuseTimer- Creates timersuseTry- Executes functions with error handling
useSsr- Handles server-side renderinguseIsClient- Checks if running on clientuseIsFirstRender- Checks if it's the first renderuseIsMounted- Checks if component is mounted
Check out our full documentation for detailed information about each hook:
# Clone the repository
git clone https://github.com/wobyjs/use
cd @woby/use
# Install dependencies
pnpm install
# Start development server (browser)
pnpm dev
# Build for production
pnpm build
# Build browser-only version
pnpm build:browser
# Build SSR-only version
pnpm build:ssr
# Run tests
pnpm test
# Serve documentation
pnpm docsThe build process creates two separate bundles:
Browser Build (dist/browser/):
index.browser.es.js(37 KB) - ES module format for modern bundlersindex.browser.umd.js(43 KB) - UMD format for direct browser usage- Full type definitions with DOM APIs (68 type files)
- Includes: All 60+ hooks (SSR-safe + browser-only)
SSR Build (dist/ssr/):
index.ssr.es.js(15 KB) - ES module formatindex.ssr.cjs.js(17 KB) - CommonJS format for Node.js- Type definitions without DOM dependencies (29 type files)
- Includes: Only 29 SSR-safe hooks
Bundle Size Comparison:
- Browser build: ~37 KB (gzipped: ~9 KB)
- SSR build: ~15 KB (gzipped: ~5 KB) - 60% smaller!
- Smaller Server Bundles - SSR build excludes 30+ browser-only hooks
- Type Safety - Prevents accidental browser API usage in SSR context
- Better Tree-Shaking - Explicit imports enable better dead code elimination
- Faster Compilation - Smaller bundles compile faster
- Clear Intent - Import paths clearly indicate environment compatibility
# Clean build (removes dist folder)
pnpm build:clean
# Build everything (browser + SSR + types)
pnpm build
# Build only browser version
pnpm build:browser
# Build only SSR version
pnpm build:ssr
# Generate TypeScript declarations
pnpm build:types
# Watch mode for development
pnpm watchThe hooks in this library are designed to work with:
- React (16.8+) - Full support for all React features
- Voby - Optimized for Voby's reactive system with JSX configuration
- Next.js - SSR-safe hooks work in Server Components, browser hooks in Client Components
- Nuxt 3 - Compatible with Nuxt's composition API
- Remix - Works with both client and server rendering
- Astro - Use SSR-safe hooks in islands, browser hooks in interactive components
Next.js:
- Default imports (
@woby/use) work in Server Components - Browser hooks require
'use client'directive - Recommended pattern: Universal components + client islands
Nuxt 3:
- Auto-imported in templates when configured
- Explicit imports needed in composables
- Use
@woby/use/ssrfor server plugins
React SPA (No SSR):
- Safe to use
@woby/use/browsereverywhere - No need to worry about server compatibility
All hooks come with full TypeScript support and type definitions included:
- ✅ Strict Mode - Full type inference
- ✅ Generics - Proper generic type handling
- ✅ Separate Types - Different types for browser vs SSR builds
- ✅ DOM Types - Only included in browser build types
- ✅ JSX Support - Configured for both React and Voby JSX
// Full type inference
const { count, increment } = useCounter(0); // count is Observable<number>
// Generic hooks
const map = useMap<string, number>(new Map()); // Map<string, number>
// Type-safe event handlers
useEventListener(window, 'resize', (event) => {
// event is inferred as UIEvent
console.log(event.target);
});Contributions are welcome! Please read our contributing guide to get started.
# Fork and clone the repository
git clone https://github.com/wobyjs/use
cd @woby/use
# Install dependencies
pnpm install
# Start development server
pnpm dev
# Run tests
pnpm test
# Build for production
pnpm build@woby/use/
├── src/
│ ├── index.ssr.tsx # SSR entry point (29 hooks)
│ ├── index.browser.tsx # Browser entry point (60+ hooks)
│ ├── useCounter/ # Individual hook folders
│ ├── useLocalStorage/
│ └── ...
├── dist/
│ ├── browser/ # Browser build output
│ │ ├── *.es.js # ES modules
│ │ ├── *.umd.js # UMD format
│ │ └── types/ # Type definitions
│ └── ssr/ # SSR build output
│ ├── *.es.js
│ ├── *.cjs.js # CommonJS
│ └── types/
├── docs/ # Documentation
├── demo/ # Example usage
└── test/ # Test suite
- Create a new folder in
src/with your hook name - Implement the hook with TypeScript
- Add tests (.test.ts or .spec.ts)
- Add documentation in
docs/hooks/ - Export from appropriate entry point:
- SSR-safe →
index.ssr.tsx - Browser-only →
index.browser.tsx
- SSR-safe →
- Update this README with hook details
- All hooks must have tests
- Use
chktesting framework - Tests run with
renderToStringfor SSR compatibility - Include both unit tests and integration examples
- Test edge cases and error conditions
- Use TypeScript strict mode
- Follow existing code formatting (Prettier)
- Write JSDoc comments for public APIs
- Keep hooks small and focused (single responsibility)
- Provide clear error messages
MIT
- Voby - A reactive JavaScript framework
- React - A JavaScript library for building user interfaces
- @woby/chk - Testing framework used by @woby/use
- @woby/vite-plugin-test - Vite plugin for testing
- GitHub Issues - Report bugs or request features
- Discussions - Ask questions and share ideas
- Twitter - Follow for updates
Made with ❤️ by the Woby Team | Documentation | Examples