2.2 KiB
useMobile() — viewport-width breakpoint hook
(no submodules)
Purpose
Returns true when the viewport width is at or below the supplied
breakpointPx (defaulting to 768px, which mirrors Tailwind's md
breakpoint). The hook subscribes to a matchMedia listener — NOT a
polling timer — so layout changes propagate without forcing a re-render
on every scroll/resize tick. SSR-safe.
Features
- Subscribes via
matchMediaso re-renders happen only on actual threshold crossings - Returns
falseserver-side (nowindow) so SSR HTML matches the desktop layout by default - Configurable breakpoint per-call site
- Cleans up the listener on unmount
Usage: Basic example
import { useMobile } from "@suaveplan/react-ui/hooks/use-mobile";
function Layout() {
const isMobile = useMobile();
return <div data-mobile={isMobile}>{isMobile ? <Drawer /> : <Sidebar />}</div>;
}
Usage: Advanced example
import { useMobile } from "@suaveplan/react-ui/hooks/use-mobile";
function ResponsiveTable() {
const isCompact = useMobile(640);
return (
<table>
<thead>
{isCompact ? <th>Item</th> : <><th>SKU</th><th>Name</th><th>Price</th></>}
</thead>
…
</table>
);
}
API Reference
useMobile(breakpointPx?: number = 768): boolean
Implementation notes
The hook holds a useState initialised by reading
window.matchMedia(...).matches synchronously inside the initialiser
when window is available — this gets the post-mount state right
without an extra render. The post-mount useEffect then calls the
listener once to sync against any state drift between SSR and the
client. The change listener tears down on unmount AND when
breakpointPx changes so a parent that swaps the breakpoint mid-life
gets a fresh subscription. The chassis defaults to 768px (Tailwind's
md boundary) but consumers picking other breakpoints get the same
zero-extra-render behaviour. Defensive guards: when matchMedia
itself throws (some restricted-permissions browsers), the listener
setup short-circuits and isMobile stays at its initial value.