useMediaQuery
A composable for reactive CSS media query matching with automatic cleanup.
Usage
The useMediaQuery composable wraps the browser’s matchMedia API, providing reactive updates when the media query state changes. It supports static strings, refs, and getter functions for dynamic queries.
Why wrap matchMedia? The native matchMedia API has no awareness of Vue’s effectScope lifecycle — change listeners you add won’t be removed when the scope is disposed. useMediaQuery integrates onScopeDispose for automatic cleanup, defers evaluation until after hydration for SSR safety, and supports reactive query strings that re-evaluate on change.
<script setup lang="ts">
import { useMediaQuery } from '@vuetify/v0'
import { shallowRef } from 'vue'
const { matches: prefersDark } = useMediaQuery('(prefers-color-scheme: dark)')
const { matches: isMobile } = useMediaQuery('(max-width: 768px)')
// Dynamic query with a reactive value
const breakpoint = shallowRef(768)
const { matches: isWide } = useMediaQuery(
() => `(min-width: ${breakpoint.value}px)`
)
</script>
<template>
<div>
<p>Dark mode: {{ prefersDark }}</p>
<p>Mobile: {{ isMobile }}</p>
<p>Wide (>= {{ breakpoint }}px): {{ isWide }}</p>
</div>
</template>Architecture
useMediaQuery wraps the browser’s matchMedia API with Vue reactivity and SSR safety:
Reactivity
| Property/Method | Reactive | Notes |
|---|---|---|
matches | ShallowRef, readonly | |
query | Computed, accepts MaybeRefOrGetter | |
mediaQueryList | ShallowRef, readonly (MediaQueryList or null) |
Dynamic queries Pass a ref or getter to useMediaQuery for dynamic query updates. The composable re-evaluates when the query changes.
Examples
Dynamic Min-Width Detection
Reactively detects landscape orientation and a slider-adjustable min-width threshold, showing how media queries update live as conditions change.
Functions
Properties
mediaQueryList
Readonly<ShallowRef<MediaQueryList | null>>The underlying MediaQueryList (null on server)