Yugen UI

useMediaQuery

useMediaQuery tracks a CSS media query (breakpoint, dark mode, reduced motion, pointer type) and re-renders when it changes.

Built on useSyncExternalStore and matchMedia, so it doesn't flicker between two values and unsubscribes on unmount. Without window it returns defaultValue. Sheet uses this hook to choose between the panel and the bottom sheet. Use it only when the behavior or the component changes; for pure layout changes, Tailwind's responsive variants (md:…) are still the better fit. It is one of the shared hooks; the others are on the Hooks page.
  • (min-width: 768px)No match
  • (prefers-color-scheme: dark)No match
  • (prefers-reduced-motion: reduce)No match
  • (pointer: coarse)No match

Import

Install from npm, copy the source into your project with @yugen-ui/cli or the shadcn CLI, or import directly when working in this repo.

TSX
// npm install yugen-uiimport { useMediaQuery } from "yugen-ui";

Variants

Each tile is a standalone example: hover to copy, or press Code to see the source.

Switch components at a breakpoint

Wide screens show the full labeled buttons; narrow screens fold them into one icon button. Resize the window to see the change.

Respect reduced motion

Behavior written in JS (scrolling, timers) has no motion-reduce: variant, so read the preference with the hook.

Wide layout

Default value during SSR

There is no matchMedia on the server: the hook returns defaultValue, then updates right after hydration.

Usage

Do
  • Use it for differences in behavior or component (Sheet panel ↔ bottom sheet, a collapsed menu).
  • Write the query in valid CSS syntax, parentheses included: "(min-width: 768px)".
  • Set defaultValue to match the server-rendered layout to reduce flicker on hydration.
Don't
  • Don't use it to switch pure layout classes. Tailwind's md: / lg: variants are cheaper and need no JS.
  • Don't create a new query on every render (a string built from state that keeps changing).
  • Don't rely on (pointer: coarse) to detect a "phone": tablets have keyboards and laptops have touch screens.

Props

Prop · TypeDefaultDescription
querystringDefault: —CSS media query, e.g. "(min-width: 768px)", "(prefers-reduced-motion: reduce)".
options.defaultValuebooleanDefault: falseValue when there is no window / matchMedia (SSR, tests).
(returns)booleanDefault: —true while the query matches; updates when that changes.