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
FAQ
Use useMediaQuery for a single custom query string like (orientation: landscape). Use useBreakpoints when you need a named set of viewport tiers shared across the whole application.
Pass a getter or a Ref<string> instead of a plain string. When the value changes, useMediaQuery disconnects the old MediaQueryList listener and attaches one for the new query. Use a plain string only when the query is constant.
Yes. usePrefersDark, usePrefersReducedMotion, and usePrefersContrast are built on useMediaQuery and wrap the matching prefers-* media features.