Skip to content

Core Concepts

Config format: MediaQueryConfig

Each breakpoint is described by a MediaQueryConfig — an array of conditions combined with AND, or a nested array of groups combined with OR.

AND (flat array)

ts
// (min-width: 768px) and (max-width: 1023px)
;[
  { type: 'min-width', value: 768 },
  { type: 'max-width', value: 1023 },
]

OR (nested array)

ts
// (max-width: 600px), (orientation: portrait) and (max-width: 1024px)
;[
  [{ type: 'max-width', value: 600 }],
  [
    { type: 'orientation', value: 'portrait' },
    { type: 'max-width', value: 1024 },
  ],
]

Raw media type

Use type: 'raw' to insert a value verbatim — useful for media types like print or screen:

ts
// Matches 'print' media type
;[{ type: 'raw', value: 'print' }][
  // screen and (max-width: 600px)
  ({ type: 'raw', value: 'screen' }, { type: 'max-width', value: 600 })
]

Supported condition types

typeExample valueGenerated query
min-width768(min-width: 768px)
max-width1023(max-width: 1023px)
min-height600(min-height: 600px)
max-height900(max-height: 900px)
orientation'portrait'(orientation: portrait)
aspect-ratio'16/9'(aspect-ratio: 16/9)
prefers-color-scheme'dark'(prefers-color-scheme: dark)
prefers-reduced-motion'reduce'(prefers-reduced-motion: reduce)
prefers-contrast'more'(prefers-contrast: more)
hover'none'(hover: none)
pointer'coarse'(pointer: coarse)
forced-colors'active'(forced-colors: active)
resolution'2dppx'(resolution: 2dppx)
display-mode'standalone'(display-mode: standalone)
raw'print'print (verbatim)

Global singleton

The library exports a pre-configured singleton responsiveState initialized with the default ResponsiveConfig (mobile / tablet / desktop).

ts
import { responsiveState, setResponsiveConfig, getResponsiveMediaQueries } from 'responsive-media'

// Re-configure the singleton
setResponsiveConfig(
  {
    sm: [{ type: 'max-width', value: 767 }],
    lg: [{ type: 'min-width', value: 1024 }],
  },
  {
    order: ['sm', 'lg'], // for isAbove / isBelow / between
    debounce: 50, // ms — throttle subscribe() listeners
  },
)

// Read a stable snapshot
const { sm, lg } = responsiveState.getState()

// Live proxy access (never debounced)
console.log(responsiveState.proxy.sm)

// Get the generated CSS strings
const mq = getResponsiveMediaQueries()
// { sm: '(max-width: 767px)', lg: '(min-width: 1024px)' }

Default config (ResponsiveConfig)

KeyRange
mobile≤ 600px
tablet601 – 960px
desktop≥ 961px

createResponsiveState: isolated instances

Create independent instances — useful for per-request SSR, multiple independent contexts, or testing:

ts
import { createResponsiveState, TailwindPreset, TailwindOrder } from 'responsive-media'

const layoutState = createResponsiveState(TailwindPreset, {
  order: [...TailwindOrder],
})

const themeState = createResponsiveState({
  dark: [{ type: 'prefers-color-scheme', value: 'dark' }],
  reducedMotion: [{ type: 'prefers-reduced-motion', value: 'reduce' }],
})

layoutState.subscribe((s) => console.log('layout:', s))
themeState.subscribe((s) => console.log('theme:', s))

// Cleanup when done (e.g. per-request SSR)
layoutState.destroy()

ContainerState: element container queries

ContainerState tracks an element's dimensions via ResizeObserver and evaluates breakpoint conditions in JavaScript — the same concept as CSS Container Queries, but in JS.

The API is identical to ReactiveResponsiveState — all subscription methods work the same way.

ts
import { createContainerState } from 'responsive-media/container'
// or: import { createContainerState } from 'responsive-media';

const card = document.querySelector('.card')!

const cardState = createContainerState(
  card,
  {
    compact: [{ type: 'max-width', value: 300 }],
    normal: [
      { type: 'min-width', value: 301 },
      { type: 'max-width', value: 599 },
    ],
    wide: [{ type: 'min-width', value: 600 }],
  },
  {
    order: ['compact', 'normal', 'wide'],
  },
)

// Reactive class toggling
cardState.on('compact', (v) => card.classList.toggle('card--compact', v))

// Sync CSS custom properties: --card-compact: 1; --card-wide: 0; …
cardState.syncCSSVars({ prefix: '--card-' })

// Get @container-compatible query strings
const strings = cardState.getMediaQueries()
// { compact: '(max-width: 300px)', wide: '(min-width: 600px)' }

// Cleanup
cardState.destroy()

Supported condition types for ContainerState

max-width, min-width, max-height, min-height, orientation, aspect-ratio