Files
2026-05-27 23:47:53 +01:00

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 matchMedia so re-renders happen only on actual threshold crossings
  • Returns false server-side (no window) 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.