Vize

media-query

Evaluate a reactive media query without requiring browser globals.

Package @vizejs/composable/media-query
Own the source vize lib pull composable:media-query
Runtime exports useMediaQuery, useReducedMotion
Gzip budget 1280 B

Minimal setup

Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).

vp install @vizejs/composable

Import the entry directly. Call lifecycle-bound utilities inside <script setup> so cleanup follows the component scope; consult the runtime contract for this entry's SSR and hydration behavior.

import { useMediaQuery, useReducedMotion } from "@vizejs/composable/media-query";

Try it

Use an actual media-query result to switch a guide list between one and two columns, with a reactive breakpoint selector.

Open the interactive example

What to observe: Resize the window across 600 pixels: the layout and visible match state change together. At 760 pixels, selecting 800 pixels switches to Compact; selecting 600 pixels restores Roomy. An iframe evaluates its own width.

The query getter follows the writable breakpoint ref. useMediaQuery returns a readonly boolean ref and uses the browser's matchMedia change events. ssrValue: false renders Compact before the browser's first post-render evaluation, so hydration starts from the same markup. Query changes replace the previous subscription, and component disposal removes the final listener. This example changes layout without animation or a simulated host.

Compare the initial and interacted states
Adapt recommended guides to available space: initial state
Initial state
Adapt recommended guides to available space: state after the verified interactions
After the verified interactions

Copy the example

Save this complete SFC in your Vue project. Its public imports and source are the same ones executed in the preview.

<script setup lang="ts">
import { ref, useId } from "vue";
import { useMediaQuery } from "@vizejs/composable/media-query";

const breakpointId = useId();
const breakpoint = ref(600);
const roomy = useMediaQuery(() => `(min-width: ${breakpoint.value}px)`, { ssrValue: false });
</script>

<template>
  <div class="composable-example">
    <label :for="breakpointId">Roomy layout starts at</label>
    <select
      :id="breakpointId"
      v-model.number="breakpoint"
      :aria-describedby="`${breakpointId}-help`"
    >
      <option :value="600">600 pixels</option>
      <option :value="800">800 pixels</option>
      <option :value="1000">1000 pixels</option>
    </select>
    <p :id="`${breakpointId}-help`">
      Resize this example's window or change the threshold. In the embedded preview, the query uses
      the preview frame's width.
    </p>
    <output aria-live="polite">Layout: {{ roomy ? "Roomy" : "Compact" }}</output>
    <p>Live query: (min-width: {{ breakpoint }}px)</p>
    <ul
      aria-label="Recommended guides"
      :style="{
        display: 'grid',
        gridTemplateColumns: roomy ? 'repeat(2, minmax(0, 1fr))' : 'minmax(0, 1fr)',
        gap: '16px',
        padding: '0',
        listStyle: 'none',
      }"
    >
      <li>
        <h3>Write components</h3>
        <p>Start with a template and add reactive behavior.</p>
      </li>
      <li>
        <h3>Check a project</h3>
        <p>Use diagnostics to catch mistakes before publishing.</p>
      </li>
    </ul>
    <p>The server renders the compact layout until the browser can evaluate the query.</p>
  </div>
</template>

Runtime contract

Utility Category Stability SSR Hydration Cleanup Targets Host globals Uses
useMediaQuery media experimental deterministic-fallback caller-managed reactive-scope web, desktop window —
useReducedMotion media experimental deterministic-fallback caller-managed reactive-scope web, desktop window useMediaQuery

API

useMediaQuery

Evaluate a reactive media query without requiring browser globals. During server rendering (or whenever no capability host resolves) the ref holds the configured server value and no subscription is created. Inside a component the first match is read after mounting, so hydration renders the server value first and never mismatches. The change subscription follows the reactive query and host: each re-evaluation removes the previous listener, and the final listener is removed when the owning reactive scope stops. Call inside an active scope so the subscription is released. A host whose matcher throws propagates the error to the active effect run; the browser default never throws.

function useMediaQuery( query: MaybeRefOrGetter<string>, options: UseMediaQueryOptions = {}, ): Readonly<Ref<boolean>>

useReducedMotion

Return the reactive user motion preference. Shares useMediaQuery semantics: during server rendering the preference is "no-preference" unless ssrValue is true, and the underlying subscription is removed when the owning reactive scope stops.

function useReducedMotion( options: UseMediaQueryOptions = {}, ): ComputedRef<MotionPreference>

Types

MediaQueryHost

Capability required to evaluate media queries.

Member Type Description
matchMedia (query: string) => MediaQueryList Create an observable result for a media query.

UseMediaQueryOptions

Options for useMediaQuery.

Member Type Description
ssrValue? boolean Value exposed when no media-query capability is available.
host? MaybeRefOrGetter<MediaQueryHost | null | undefined> Reactive media-query capability for alternate runtimes and tests.