JAVASCRIPT
Building a Responsive Design Composable with Vue 3 `useMediaQuery`
Create a custom Vue 3 composable (`useMediaQuery`) to reactively track CSS media query states, enabling responsive logic in your components and abstracting away `window.matchMedia` details.
// composables/useMediaQuery.js
import { ref, onMounted, onUnmounted } from 'vue';
export function useMediaQuery(query) {
const matches = ref(false);
let mediaQueryList;
const updateMatches = (event) => {
matches.value = event.matches;
};
onMounted(() => {
if (typeof window !== 'undefined' && window.matchMedia) {
mediaQueryList = window.matchMedia(query);
matches.value = mediaQueryList.matches;
mediaQueryList.addEventListener('change', updateMatches);
}
});
onUnmounted(() => {
if (mediaQueryList) {
mediaQueryList.removeEventListener('change', updateMatches);
}
});
return matches;
}
// ComponentUsingMediaQuery.vue
<template>
<div :class="{ 'mobile-layout': isMobile, 'desktop-layout': !isMobile }">
<h3 v-if="isMobile">Mobile View</h3>
<h3 v-else>Desktop View</h3>
<p>Screen is {{ isMobile ? 'small' : 'large' }}.</p>
</div>
</template>
<script setup>
import { useMediaQuery } from './composables/useMediaQuery';
const isMobile = useMediaQuery('(max-width: 768px)');
</script>
<style scoped>
.mobile-layout {
background-color: #ffe0b2;
border: 1px solid orange;
padding: 20px;
}
.desktop-layout {
background-color: #c8e6c9;
border: 1px solid green;
padding: 20px;
}
</style>
How it works: This snippet provides a `useMediaQuery` composable for Vue 3 that allows components to reactively respond to CSS media query changes. The `useMediaQuery` function takes a media query string (e.g., `(max-width: 768px)`) and returns a reactive `ref` that indicates whether the query currently matches. It utilizes `window.matchMedia` to listen for changes. The `onMounted` and `onUnmounted` lifecycle hooks ensure that the event listener is properly attached and detached, preventing memory leaks. `ComponentUsingMediaQuery.vue` demonstrates how to consume this composable to apply different styles or render different content based on the screen size, centralizing responsive logic.