Vuetify 3: useBreakpoint() vs Manual Resize Listeners for Responsive Visibility
Use Vuetify 3's useBreakpoint() composable for SSR-safe responsive visibility instead of manual window listeners or duplicated CSS breakpoints.
07 May 2026, 16:17 UTC

Decision and constraints
You need to show or hide a UI section based on screen width in a Vuetify 3 application. A common mistake is adding a custom window resize listener or matchMedia check inside a component. That approach can leak event listeners, cause hydration mismatches during server-side rendering (SSR), and duplicate breakpoint values already managed by Vuetify.
Use Vuetify 3's useBreakpoint() composable instead. It returns reactive booleans for Vuetify's configured breakpoints, works inside Vue 3's Composition API, and is safe for SSR because it does not touch window directly during initial render.
Constraints: Vuetify 3.x, Vue 3 Composition API, SSR-safe rendering, no direct DOM manipulation, and one source of truth for breakpoint thresholds.
Supported options compared
| Option | Best for | Main risk |
|---|---|---|
| useBreakpoint() from 'vuetify' | Reactive conditional rendering tied to Vuetify breakpoints | Couples component logic to Vuetify's breakpoint config |
| Scoped CSS media queries | Purely visual show/hide without JavaScript state | Not reactive to Vue state; thresholds can drift from Vuetify config |
| Manual window.matchMedia or resize listener | Custom thresholds outside Vuetify | Hydration mismatches, listener leaks, duplicated breakpoint values |
Trade-offs
useBreakpoint() is SSR-safe and keeps breakpoints in Vuetify's configuration, but your component becomes coupled to Vuetify's breakpoint names. If your design system later moves to a different UI library, you would need to replace these calls. CSS media queries are framework-agnostic and perform well for visual toggling, yet they cannot drive v-if or other Vue logic, so they are unsuitable when you need to conditionally mount a component. Manual listeners give full control over pixel thresholds, but you must add and remove the listener yourself and guard against SSR hydration errors. They also duplicate breakpoint values that Vuetify already tracks.
Implementation: show a sidebar at md and above
This example renders a sidebar only when the viewport meets Vuetify's md breakpoint and larger. The default md threshold is 1024px.
<script setup>
import { useBreakpoint } from 'vuetify'
const { mdAndUp } = useBreakpoint()
</script>
<template>
<aside v-if='mdAndUp'>
Sidebar navigation
</aside>
</template>
Run this inside a Vue single-file component using <script setup>. Do not call useBreakpoint() in a plain JavaScript module outside a Vue setup function; it will not have access to the component's reactive context.
Where to run: your application source tree. Required permissions: none beyond normal file write access. Expected check: resizing the browser past 1024px makes the sidebar appear; shrinking below it removes the element from the DOM. Risk: if you customize Vuetify breakpoints in your theme, mdAndUp follows those values, not a hardcoded 1024px.
Keep breakpoints in sync
If you customize Vuetify breakpoints, update them in your Vuetify setup and in any CSS media queries that use the same pixel thresholds. A mismatch means useBreakpoint() might report mdAndUp as true while a CSS rule still hides the element, or vice versa. Treat Vuetify's breakpoint config as the single source of truth and derive custom CSS from it rather than hardcoding pixels in multiple places.
Validate the behavior
- Open a terminal in the project root and run npm list vuetify. Confirm the output shows vuetify@3.x.x. This guide does not apply to Vuetify 2.
- Start the development server, typically npm run dev for Vite or Nuxt.
- Open the page containing the component. Use browser device tools or drag the window edge past the configured md width.
- Confirm the sidebar toggles without console warnings about hydration mismatches.
- If you customized breakpoints, verify the toggle point matches your configured value, not the default 1024px.
Practical check: install Vue Devtools, inspect the component, and confirm mdAndUp flips between true and false as you cross the breakpoint.
Limitations
- useBreakpoint() only works inside setup() or <script setup>.
- Default Vuetify breakpoints are xs, sm, md, lg, xl, and xxl. If your CSS uses different pixel thresholds, align them in your Vuetify setup.
- Do not layer v-if breakpoint logic and custom matchMedia classes on the same element; conflicting rules can cause flicker.
Rollback
This change only edits component source code. If it causes issues, revert the commit and redeploy. No database or infrastructure state is modified.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.