Hooks and utilities
Six focused React hooks for state, browser capabilities and small interactions. Import only the hook you use. Each hook needs React as a peer.
useDebounce
Returns the initial value immediately, then waits for input to settle before updating. Useful for search queries; a new value restarts the timer.
| Signature |
|---|
useDebounce<T>(value: T, delayMs = 300): T |
import { useDebounce } from "@kongmy-dev/sapphire-ui/hooks/use-debounce";
const debouncedQuery = useDebounce(query, 300);useMediaQuery
Subscribes to a media query. Starts false on the server and first render, then reads the browser match after mounting. Prefer CSS for layout changes.
| Signature |
|---|
useMediaQuery(query: string): boolean |
import { useMediaQuery } from "@kongmy-dev/sapphire-ui/hooks/use-media-query";
const reducedMotion = useMediaQuery("(prefers-reduced-motion: reduce)");useLocalStorage
Uses the fallback on the server and first render, then reads storage after mounting. The required parser validates stored JSON. Invalid or unavailable storage falls back safely; storage events sync other tabs.
| Signature |
|---|
useLocalStorage<T>(key: string, fallback: T, parse: (value: unknown) => T): [T, Dispatch<SetStateAction<T>>] |
import { useLocalStorage } from "@kongmy-dev/sapphire-ui/hooks/use-local-storage";
const [compact, setCompact] = useLocalStorage(
"compact", false, (value) => value === true,
);useOnClickOutside
Listens for mouse down, touch start and focus moving outside the referenced element. Uses the composed event path for shadow DOM. Pass false or null to disable the handler.
| Signature |
|---|
useOnClickOutside<T extends HTMLElement>(ref: RefObject<T | null>, handler: ((event: MouseEvent | TouchEvent | FocusEvent) => void) | null | false): void |
import { useOnClickOutside } from "@kongmy-dev/sapphire-ui/hooks/use-on-click-outside";
const panelRef = useRef<HTMLDivElement>(null);
useOnClickOutside(panelRef, open ? () => setOpen(false) : false);useCopyToClipboard
Copies text with the browser Clipboard API. copy resolves false if access is unavailable or denied. Successful feedback resets after resetMs; use the returned boolean to report failures.
| Signature |
|---|
useCopyToClipboard({ resetMs = 2000 } = {}): { copied: string | null; isCopied: boolean; copy(text: string): Promise<boolean> } |
import { useCopyToClipboard } from "@kongmy-dev/sapphire-ui/hooks/use-copy-to-clipboard";
const { copy, isCopied } = useCopyToClipboard();
const succeeded = await copy("Hello");useIsomorphicLayoutEffect
Uses useLayoutEffect in a browser and useEffect on the server. Reserve it for measurements that must complete before paint; return a cleanup when subscribing.
| Signature |
|---|
useIsomorphicLayoutEffect(effect: EffectCallback, deps?: DependencyList): void |
import { useIsomorphicLayoutEffect } from "@kongmy-dev/sapphire-ui/hooks/use-isomorphic-layout-effect";
useIsomorphicLayoutEffect(() => {
setWidth(panelRef.current?.getBoundingClientRect().width ?? 0);
}, []);