React Integration
Import from responsive-media/react.
import {
useResponsive,
useBreakpoints,
useMediaQuery,
useContainerState,
} from 'responsive-media/react'Typed hooks from your config
defineResponsive(config, options?)
Applies config to the shared state and returns useResponsive, useBreakpoints and useResponsiveValue, with the state and the breakpoint keys inferred from config — no generic to write by hand. Put the call in one module and import the hooks from there.
// responsive.ts
import { defineResponsive } from 'responsive-media/react'
export const { useResponsive, useBreakpoints } = defineResponsive(
{
mobile: [{ type: 'max-width', value: 600 }],
smallTablet: [{ type: 'max-width', value: 850 }],
desktop: [{ type: 'min-width', value: 961 }],
},
{ order: ['mobile', 'smallTablet', 'desktop'] },
)useResponsive()returns{ mobile: boolean; smallTablet: boolean; desktop: boolean }.useBreakpoints()accepts only those keys:isAbove('nope')is a compile error, andcurrentis'mobile' | 'smallTablet' | 'desktop' | null.
The call replaces the configuration an earlier setResponsiveConfig() set, because they share one state.
Responsive State
useResponsive<T>()
Returns the current responsive state. Re-renders only when state changes. Uses useSyncExternalStore internally. Accepts a generic type parameter to narrow the returned state — see ConfigToState<T>.
import { useResponsive } from 'responsive-media/react'
type MyState = { sm: boolean; lg: boolean }
function App() {
const { sm, lg } = useResponsive<MyState>()
return sm ? <MobileNav /> : <DesktopNav />
}Breakpoint Helpers
useBreakpoints()
Returns ordered breakpoint helpers. Re-renders when the responsive state changes.
import { useBreakpoints } from 'responsive-media/react'
function Nav() {
const { current, isAbove, isBelow, between } = useBreakpoints()
return (
<>
<span>Current: {current}</span>
{isAbove('sm') ? <DesktopNav /> : <MobileNav />}
{between('sm', 'lg') && <TabletBanner />}
</>
)
}Unlike Vue,
currentis a plainstring | null(not a ref). Re-renders are triggered byuseSyncExternalStore.
Media Query
useMediaQuery(query)
boolean
Tracks a raw CSS media query string. SSR-safe (returns false on the server).
import { useMediaQuery } from 'responsive-media/react'
function ThemeToggle() {
const isDark = useMediaQuery('(prefers-color-scheme: dark)')
const canHover = useMediaQuery('(hover: hover)')
return <button className={isDark ? 'dark' : 'light'}>Toggle</button>
}Container State
useContainerState(ref, config, options?)
Tracks an element's dimensions and returns a state object whose keys are inferred from config. Sets up and tears down ResizeObserver via useEffect.
import { useRef } from 'react'
import { useContainerState } from 'responsive-media/react'
function Card() {
const ref = useRef<HTMLDivElement>(null)
const { compact, wide } = useContainerState(ref, {
compact: [{ type: 'max-width', value: 300 }],
wide: [{ type: 'min-width', value: 600 }],
})
return (
<div ref={ref}>{compact ? <CompactLayout /> : wide ? <WideLayout /> : <DefaultLayout />}</div>
)
}
configandoptionsare treated as static after mount. Wrap inuseMemoif they change.
If the target element isn't attached yet when this hook first runs (e.g. it's behind a later-mounted conditional or a portal), it doesn't give up — a bounded
requestAnimationFrameretry loop keeps checking the ref until the element resolves, then sets up theResizeObserver.
Responsive Values
useResponsiveValue(map, fallback?)
T | undefined
Returns the value of the first active breakpoint in map, or fallback when none is active. The order of map decides: the first key that is true wins, so when breakpoints overlap, list the narrowest one first.
import { useResponsiveValue } from 'responsive-media/react'
function Gallery() {
const columns = useResponsiveValue({ mobile: 1, tablet: 2, desktop: 4 })
return <Grid columns={columns} />
}With the hooks from defineResponsive() the keys of map are checked against your config.
User Preferences
useUserPreferences()
{ dark, light, reducedMotion, highContrast, lowContrast, noHover, coarsePointer, forcedColors, print }
The user's appearance and accessibility preferences — the AccessibilityPreset as ready state, with nothing to configure. It reads a state of its own, so it never interferes with your breakpoints. Every key is false on the server.
import { useUserPreferences } from 'responsive-media/react'
function Hero() {
const { reducedMotion } = useUserPreferences()
return reducedMotion ? <StillImage /> : <Parallax />
}Viewport Size
useViewportSize(options?)
{ width: number; height: number }
The window size in pixels, for the moments you need the number and not a breakpoint. It is 0 by 0 on the server, and the object keeps its identity between renders until the size changes.
throttle—number· default:100. Milliseconds between updates while the window is resized;0updates on every event.
Hydration
While React hydrates, the hooks return the server snapshot (getSsrState()), so the first client render matches the server HTML and React then re-renders with the real value without a recoverable error. Set ssrState to choose what the server renders — see SSR & Hydration.