Skip to main content
Dynamic UI provides hooks for responsive design that work with SSR and support optional listeners for real-time updates.

useMediaQuery

A low-level hook that checks if a media query matches using React 18’s useSyncExternalStore.

Import

import { useMediaQuery } from '@dynamic-framework/ui-react';

Signature

function useMediaQuery(
  mediaQuery: string,
  useListener?: boolean
): boolean

Parameters

mediaQuery
string
required
A CSS media query string (e.g., "(min-width: 768px)")
useListener
boolean
default:false
Whether to subscribe to media query changes. When false, the query is only evaluated on mount.

Return Value

matches
boolean
true if the media query matches, false otherwise

Usage

Basic Usage

import { useMediaQuery } from '@dynamic-framework/ui-react';

function ResponsiveComponent() {
  const isMobile = useMediaQuery('(max-width: 768px)');

  return (
    <div>
      {isMobile ? <MobileView /> : <DesktopView />}
    </div>
  );
}

With Live Updates

import { useMediaQuery } from '@dynamic-framework/ui-react';

function DynamicLayout() {
  // Re-renders when viewport size changes
  const isWide = useMediaQuery('(min-width: 1200px)', true);

  return (
    <div className={isWide ? 'wide-layout' : 'narrow-layout'}>
      <h1>Window width is {isWide ? 'wide' : 'narrow'}</h1>
    </div>
  );
}

Multiple Media Queries

import { useMediaQuery } from '@dynamic-framework/ui-react';

function AdaptiveComponent() {
  const isMobile = useMediaQuery('(max-width: 576px)', true);
  const isTablet = useMediaQuery(
    '(min-width: 577px) and (max-width: 992px)',
    true
  );
  const isDesktop = useMediaQuery('(min-width: 993px)', true);

  if (isMobile) return <MobileLayout />;
  if (isTablet) return <TabletLayout />;
  if (isDesktop) return <DesktopLayout />;
  
  return null;
}

Orientation Detection

import { useMediaQuery } from '@dynamic-framework/ui-react';

function OrientationAware() {
  const isPortrait = useMediaQuery('(orientation: portrait)', true);

  return (
    <div>
      Device is in {isPortrait ? 'portrait' : 'landscape'} mode
    </div>
  );
}

useMediaBreakpointUp

A higher-level hook that checks if the viewport is at or above a specific breakpoint defined in DContext.

Import

import {
  useMediaBreakpointUpXs,
  useMediaBreakpointUpSm,
  useMediaBreakpointUpMd,
  useMediaBreakpointUpLg,
  useMediaBreakpointUpXl,
  useMediaBreakpointUpXxl,
} from '@dynamic-framework/ui-react';

Signature

function useMediaBreakpointUpXs(useListener?: boolean): boolean
function useMediaBreakpointUpSm(useListener?: boolean): boolean
function useMediaBreakpointUpMd(useListener?: boolean): boolean
function useMediaBreakpointUpLg(useListener?: boolean): boolean
function useMediaBreakpointUpXl(useListener?: boolean): boolean
function useMediaBreakpointUpXxl(useListener?: boolean): boolean

Parameters

useListener
boolean
default:false
Whether to subscribe to viewport changes. When false, the breakpoint is only checked on mount.

Return Value

matches
boolean
true if the viewport width is at or above the breakpoint, false otherwise

Breakpoints

The breakpoint values are read from DContext and typically match Bootstrap’s defaults:
type BreakpointProps = {
  xs: string;   // Extra small (default: "0px")
  sm: string;   // Small (default: "576px")
  md: string;   // Medium (default: "768px")
  lg: string;   // Large (default: "992px")
  xl: string;   // Extra large (default: "1200px")
  xxl: string;  // Extra extra large (default: "1400px")
}

Usage

Basic Breakpoint Check

import { useMediaBreakpointUpMd } from '@dynamic-framework/ui-react';

function ResponsiveNav() {
  const isMdOrLarger = useMediaBreakpointUpMd();

  return (
    <nav>
      {isMdOrLarger ? <FullNavigation /> : <HamburgerMenu />}
    </nav>
  );
}

Conditional Rendering

import {
  useMediaBreakpointUpSm,
  useMediaBreakpointUpLg
} from '@dynamic-framework/ui-react';

function Dashboard() {
  const isSmOrLarger = useMediaBreakpointUpSm(true);
  const isLgOrLarger = useMediaBreakpointUpLg(true);

  return (
    <div>
      <MainContent />
      {isSmOrLarger && <Sidebar />}
      {isLgOrLarger && <AdditionalPanel />}
    </div>
  );
}

Responsive Grid Columns

import {
  useMediaBreakpointUpMd,
  useMediaBreakpointUpXl
} from '@dynamic-framework/ui-react';

function ProductGrid({ products }) {
  const isMd = useMediaBreakpointUpMd(true);
  const isXl = useMediaBreakpointUpXl(true);

  const columns = isXl ? 4 : isMd ? 3 : 1;

  return (
    <div style={{ display: 'grid', gridTemplateColumns: `repeat(${columns}, 1fr)` }}>
      {products.map(product => (
        <ProductCard key={product.id} product={product} />
      ))}
    </div>
  );
}

Mobile-First Design

import {
  useMediaBreakpointUpSm,
  useMediaBreakpointUpMd,
  useMediaBreakpointUpLg
} from '@dynamic-framework/ui-react';

function AdaptiveCard() {
  const isSm = useMediaBreakpointUpSm(true);
  const isMd = useMediaBreakpointUpMd(true);
  const isLg = useMediaBreakpointUpLg(true);

  return (
    <div
      style={{
        padding: isLg ? '32px' : isMd ? '24px' : isSm ? '16px' : '12px',
        fontSize: isLg ? '18px' : isMd ? '16px' : '14px'
      }}
    >
      <h2>Responsive Card</h2>
      <p>Content adapts to screen size</p>
    </div>
  );
}

Context Setup

The useMediaBreakpointUp hooks require DContextProvider:
import { DContextProvider } from '@dynamic-framework/ui-react';

function App() {
  return (
    <DContextProvider
      // Breakpoints are automatically read from CSS custom properties
      // but can be overridden if needed
    >
      <YourApp />
    </DContextProvider>
  );
}

SSR Support

Both hooks use useSyncExternalStore with proper server-side rendering support:
  • During SSR, useMediaQuery returns false by default
  • useListener={false} prevents hydration mismatches by only checking on mount
  • useListener={true} enables real-time updates but may cause initial hydration differences

SSR Best Practices

import { useMediaQuery } from '@dynamic-framework/ui-react';
import { useEffect, useState } from 'react';

function SSRSafeComponent() {
  const [mounted, setMounted] = useState(false);
  const isMobile = useMediaQuery('(max-width: 768px)', mounted);

  useEffect(() => {
    setMounted(true);
  }, []);

  if (!mounted) {
    // Return server-safe fallback
    return <DefaultView />;
  }

  return isMobile ? <MobileView /> : <DesktopView />;
}

Performance

  • Without listener (useListener={false}): Zero runtime overhead after initial render
  • With listener (useListener={true}): Uses efficient matchMedia API with automatic cleanup
  • Breakpoint hooks are memoized and only re-compute when breakpoint values change

Build docs developers (and LLMs) love