A collection of modern, tree-shakable React hooks for everyday development.
npm install usehooks-react
# or
yarn add usehooks-react
# or
pnpm add usehooks-react| Hook | Description |
|---|---|
useLocalStorage |
Sync state with localStorage with type safety |
useDebounce |
Debounce a rapidly changing value |
useToggle |
Simple boolean toggle with helpers |
useClickOutside |
Detect clicks outside a referenced element |
useMediaQuery |
Track a CSS media query match state |
useFetch |
Declarative data fetching with loading/error states |
useEventListener |
Attach event listeners with automatic cleanup |
useWindowSize |
Track the browser window dimensions |
usePrevious |
Keep track of the previous value of state/props |
useClipboard |
Copy text to clipboard with success feedback |
useOnlineStatus |
Track whether the user is online or offline |
import { useLocalStorage } from 'usehooks-react';
function App() {
const [name, setName] = useLocalStorage('user-name', 'Guest');
return <input value={name} onChange={(e) => setName(e.target.value)} />;
}import { useDebounce } from 'usehooks-react';
function SearchBar() {
const [query, setQuery] = useState('');
const debouncedQuery = useDebounce(query, 300);
useEffect(() => {
// API call only fires after 300ms of inactivity
fetchResults(debouncedQuery);
}, [debouncedQuery]);
return <input value={query} onChange={(e) => setQuery(e.target.value)} />;
}import { useToggle } from 'usehooks-react';
function Modal() {
const [isOpen, toggle, open, close] = useToggle(false);
return (
<>
<button onClick={open}>Open</button>
{isOpen && <div onClick={close}>Modal content — click to close</div>}
</>
);
}import { useClickOutside } from 'usehooks-react';
function Dropdown() {
const ref = useRef<HTMLDivElement>(null);
const [open, setOpen] = useState(false);
useClickOutside(ref, () => setOpen(false));
return open ? <div ref={ref}>Menu items...</div> : null;
}import { useMediaQuery } from 'usehooks-react';
function Layout() {
const isMobile = useMediaQuery('(max-width: 768px)');
return isMobile ? <MobileNav /> : <DesktopNav />;
}import { useFetch } from 'usehooks-react';
interface User { id: number; name: string; }
function UserList() {
const { data, loading, error, refetch } = useFetch<User[]>('/api/users');
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error}</p>;
return (
<ul>
{data?.map((u) => <li key={u.id}>{u.name}</li>)}
<button onClick={refetch}>Refresh</button>
</ul>
);
}import { useWindowSize } from 'usehooks-react';
function App() {
const { width, height } = useWindowSize();
return <p>Viewport: {width} x {height}</p>;
}import { useClipboard } from 'usehooks-react';
function CopyButton({ text }: { text: string }) {
const { copied, copy } = useClipboard();
return (
<button onClick={() => copy(text)}>
{copied ? 'Copied!' : 'Copy'}
</button>
);
}import { useOnlineStatus } from 'usehooks-react';
function StatusBar() {
const isOnline = useOnlineStatus();
return <span>{isOnline ? '🟢 Online' : '🔴 Offline'}</span>;
}Each hook can be imported individually to keep your bundle small:
import { useDebounce } from 'usehooks-react'; // Only useDebounce is bundled
import { useMediaQuery } from 'usehooks-react'; // Only useMediaQuery is bundled- React 17+ (including React 18)
- TypeScript 4.5+ (optional but recommended)
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feat/my-new-hook) - Commit your changes (
git commit -m 'feat: add useMyHook') - Push to the branch (
git push origin feat/my-new-hook) - Open a Pull Request
MIT — Made with ❤️ by Ali Mahmoud