Skip to main content
Subscribes to a CSS media query and reports whether it currently matches. Supports an optional fallback value and deferred initial evaluation for SSR-friendly behavior.

Usage

import { useMediaQuery } from '@kuzenbo/hooks';

function Demo() {
  const matches = useMediaQuery('(max-width: 768px)');

  return (
    <div>
      {matches ? 'Mobile view' : 'Desktop view'}
    </div>
  );
}

Function Signature

function useMediaQuery(
  query: string,
  initialValue?: boolean,
  options?: UseMediaQueryOptions
): boolean

Parameters

query
string
required
Media query string passed to window.matchMedia. Example: '(max-width: 768px)'.
initialValue
boolean
Optional fallback value used before the query is evaluated. Useful for SSR or initial render.
options
UseMediaQueryOptions
Controls whether the initial query read happens in an effect.
options.getInitialValueInEffect
boolean
If true, the initial query evaluation happens in an effect for SSR safety. Defaults to true.

Return Value

matches
boolean
Boolean indicating whether the media query currently matches.

Examples

Responsive Layout

import { useMediaQuery } from '@kuzenbo/hooks';

function ResponsiveLayout() {
  const isMobile = useMediaQuery('(max-width: 768px)');
  const isTablet = useMediaQuery('(min-width: 769px) and (max-width: 1024px)');
  const isDesktop = useMediaQuery('(min-width: 1025px)');

  return (
    <div>
      {isMobile && <MobileLayout />}
      {isTablet && <TabletLayout />}
      {isDesktop && <DesktopLayout />}
    </div>
  );
}

Dark Mode Detection

import { useMediaQuery } from '@kuzenbo/hooks';

function ThemeDetector() {
  const prefersDark = useMediaQuery('(prefers-color-scheme: dark)');

  return (
    <div className={prefersDark ? 'dark-theme' : 'light-theme'}>
      Current theme: {prefersDark ? 'Dark' : 'Light'}
    </div>
  );
}

Reduced Motion Preference

import { useMediaQuery } from '@kuzenbo/hooks';

function AnimatedComponent() {
  const prefersReducedMotion = useMediaQuery('(prefers-reduced-motion: reduce)');

  return (
    <div
      style={{
        transition: prefersReducedMotion ? 'none' : 'all 0.3s ease',
      }}
    >
      Content
    </div>
  );
}

Portrait/Landscape Orientation

import { useMediaQuery } from '@kuzenbo/hooks';

function OrientationDetector() {
  const isPortrait = useMediaQuery('(orientation: portrait)');

  return (
    <div>
      Current orientation: {isPortrait ? 'Portrait' : 'Landscape'}
    </div>
  );
}

High Resolution Display

import { useMediaQuery } from '@kuzenbo/hooks';

function RetinaImage() {
  const isRetina = useMediaQuery('(min-resolution: 2dppx)');

  return (
    <img
      src={isRetina ? '/[email protected]' : '/image.png'}
      alt="Responsive image"
    />
  );
}

SSR-Safe with Initial Value

import { useMediaQuery } from '@kuzenbo/hooks';

function SSRSafeComponent() {
  const isMobile = useMediaQuery(
    '(max-width: 768px)',
    false, // Initial value for SSR
    { getInitialValueInEffect: true }
  );

  return <div>{isMobile ? 'Mobile' : 'Desktop'}</div>;
}

Multiple Breakpoints

import { useMediaQuery } from '@kuzenbo/hooks';

function BreakpointDisplay() {
  const breakpoints = {
    xs: useMediaQuery('(max-width: 639px)'),
    sm: useMediaQuery('(min-width: 640px) and (max-width: 767px)'),
    md: useMediaQuery('(min-width: 768px) and (max-width: 1023px)'),
    lg: useMediaQuery('(min-width: 1024px) and (max-width: 1279px)'),
    xl: useMediaQuery('(min-width: 1280px)'),
  };

  const currentBreakpoint = Object.keys(breakpoints).find(
    (key) => breakpoints[key as keyof typeof breakpoints]
  );

  return <div>Current breakpoint: {currentBreakpoint}</div>;
}

Build docs developers (and LLMs) love