Supercharge Your Vue.js and Nuxt.js Apps with VueUse

Discover how VueUse's 200+ composable functions can transform your Vue 3 and Nuxt.js development workflow with ready-made solutions for common patterns.

What is VueUse?

VueUse is an open-source library that offers a comprehensive set of composable functions designed specifically for Vue 3 and the Composition API. Each composable encapsulates a specific piece of functionality--from simple ref manipulations to complex browser API integrations--making it easy to add sophisticated features to your applications with minimal code.

What sets VueUse apart is its commitment to three core principles: being fully tree-shakeable so you only include what you need, providing excellent TypeScript support with full type definitions, and maintaining SSR (Server-Side Rendering) compatibility for frameworks like Nuxt.js. These design decisions mean VueUse integrates seamlessly into both small projects and large-scale applications without adding unnecessary bundle size or compatibility issues.

For teams working with Nuxt.js, VueUse becomes even more valuable through the official @vueuse/nuxt module, which provides automatic importing of all composables. This eliminates import statements cluttering your codebase while ensuring you always use the most up-to-date versions of the utilities you need.

When building modern Vue applications, leveraging battle-tested composables like VueUse can significantly reduce development time while improving code quality and maintainability across your projects.

Why Use VueUse in Your Projects

Leverage battle-tested implementations

200+ Composable Functions

Comprehensive utilities for state, elements, browsers, sensors, and more

Fully Tree-Shakeable

Only bundle the composables you actually use

TypeScript Support

Full type definitions with excellent inference

SSR Compatible

Works seamlessly with Nuxt.js server-side rendering

Getting Started with VueUse

Installation

For Vue 3 projects:

npm install @vueuse/core

For Nuxt.js projects:

npm install @vueuse/nuxt @vueuse/core

Nuxt Configuration

Add the module to your nuxt.config.ts:

export default defineNuxtConfig({
 modules: ['@vueuse/nuxt']
})

With this configuration, all VueUse composables become automatically available throughout your application without explicit imports, reducing boilerplate while maintaining full TypeScript support.

Core Composables: State Management

VueUse provides several composables for managing reactive state, going beyond Vue's built-in ref and reactive to handle persistent and synchronized state across components or browser sessions.

useStorage

The useStorage composable automatically synchronizes reactive state with browser localStorage or sessionStorage. Unlike manual storage implementations that require serialization/deserialization and event listeners for cross-tab synchronization, useStorage handles all these concerns automatically:

import { useStorage } from '@vueuse/core'

// Persist state to localStorage automatically
const settings = useStorage('user-settings', {
 theme: 'light',
 fontSize: 16,
 notifications: true
})

// Changes automatically persist and sync across tabs
settings.value.theme = 'dark'

The composable supports JSON serialization, handles browser storage limits gracefully, and automatically synchronizes state across multiple browser tabs using the storage event. For sensitive data or when localStorage isn't available, it seamlessly falls back to in-memory state.

useGlobalState

Another powerful state management composable is createGlobalState, which provides a simple global state management solution without external libraries. This is particularly useful for sharing state across distant components without prop drilling:

import { createGlobalState } from '@vueuse/core'

// Create a global state that can be used anywhere
const useGlobalCounter = createGlobalState(() => ref(0))

// In any component
const counter = useGlobalCounter()

For applications requiring more sophisticated state management, VueUse integrates well with Pinia or Vuex while providing utility composables that enhance these libraries' capabilities.

Core Composables: Element Interactions

Interacting with DOM elements is a common requirement in Vue applications, and VueUse provides composables that make these interactions intuitive and reactive.

useElementSize

The useElementSize composable tracks the dimensions of any DOM element, updating reactively as the element resizes. This is invaluable for responsive designs where components need to adapt their layout based on available space:

import { useElementSize } from '@vueuse/core'

const cardRef = ref<HTMLElement | null>(null)
const { width, height } = useElementSize(cardRef)

watch(width, (newWidth) => {
 // Adapt layout based on available width
 columns.value = newWidth > 600 ? 3 : 1
})

useDraggable

The useDraggable composable enables drag-and-drop functionality with minimal configuration, returning position coordinates and drag state that integrate naturally with Vue's reactivity system:

import { useDraggable } from '@vueuse/core'

const elementRef = ref<HTMLElement | null>(null)
const { x, y, isDragging } = useDraggable(elementRef, {
 initialValue: { x: 100, y: 100 }
})

onClickOutside

For implementing modals, dropdowns, or tooltips that should close when users click outside them, onClickOutside provides a clean solution:

import { onClickOutside } from '@vueuse/core'

const modalRef = ref<HTMLElement | null>(null)

onClickOutside(modalRef, () => {
 // Close modal when clicking outside
 emit('close')
})

Implementing this feature manually requires understanding the DOM event model, managing event listener cleanup to prevent memory leaks, and handling various edge cases like iframe interactions. VueUse's onClickOutside encapsulates all this complexity.

Browser and Window Composables

VueUse includes extensive support for browser APIs, making it easy to reactively access browser state and respond to user environment changes.

Dark Mode with useDark

import { useDark, useToggle } from '@vueuse/core'

// Automatically detect and respect system preference
const isDark = useDark()
const toggleDark = useToggle(isDark)

// Toggle in your template
<button @click="toggleDark()">
 {{ isDark ? 'Switch to Light Mode' : 'Switch to Dark Mode' }}
</button>

useMediaQuery

The useMediaQuery composable enables reactive CSS media query handling:

import { useMediaQuery } from '@vueuse/core'

const isLargeScreen = useMediaQuery('(min-width: 1024px)')
const prefersReducedMotion = useMediaQuery('(prefers-reduced-motion: reduce)')

Scroll Tracking

For tracking scroll position and implementing scroll-dependent features, useWindowScroll and useScroll provide reactive access to scroll coordinates:

import { useWindowScroll, useScroll } from '@vueuse/core'

const { y: scrollY } = useWindowScroll()
const elementRef = ref<HTMLElement | null>(null)
const { y: elementScrollY } = useScroll(elementRef)

useClipboard

The useClipboard composable abstracts the Clipboard API with graceful fallbacks for older browsers:

import { useClipboard } from '@vueuse/core'

const { copy, copied } = useClipboard()

const copyToClipboard = async (text: string) => {
 await copy(text)
 // Use 'copied' ref to show feedback
}

Sensor and Event Composables

VueUse provides several composables for tracking user input, enabling sophisticated interactive features without manual event management.

Mouse Tracking

import { useMouse, useMouseInElement } from '@vueuse/core'

// Track mouse position relative to viewport
const { x, y } = useMouse()

// Track mouse position relative to an element
const elementRef = ref<HTMLElement | null>(null)
const { x: elementX, y: elementY, isOutside } = useMouseInElement(elementRef)

This composable is particularly useful for implementing custom cursors, parallax effects, and hover-dependent features that need precise mouse position information.

useSwipe

The useSwipe composable detects swipe gestures on touch devices, supporting both touch and mouse drag events:

import { useSwipe } from '@vueuse/core'

const elementRef = ref<HTMLElement | null>(null)
const { isSwiping, direction, lengthX, lengthY } = useSwipe(elementRef, {
 onSwipeEnd: () => {
 if (direction.value === 'left') {
 navigateToPrevious()
 } else if (direction.value === 'right') {
 navigateToNext()
 }
 }
})

useMagicKeys

The useMagicKeys composable provides a powerful interface for tracking keyboard shortcuts and key combinations:

import { useMagicKeys, whenever } from '@vueuse/core'

const { Ctrl_K, Shift_Escape, a, b } = useMagicKeys()

// Watch for specific key combinations
whenever(Ctrl_K.value, () => {
 openCommandPalette()
})

// Complex combination: Ctrl+Shift+A or Ctrl+B
whenever(
 (Ctrl_K.value && Shift_Escape.value) || (Ctrl_K.value && b.value),
 () => {
 // Handle the combination
 }
)

Integrating VueUse with Nuxt.js

Automatic Imports

The @vueuse/nuxt module transforms how you work with composables in Nuxt applications by providing automatic imports. This means you can use any VueUse composable without importing it, and Nuxt's build process will automatically include only what you actually use:

// nuxt.config.ts
export default defineNuxtConfig({
 modules: ['@vueuse/nuxt'],
 vueuse: {
 // Optional configuration
 autoImports: true,
 imports: ['useMouse', 'useDark', 'useStorage']
 }
})

In your Vue components and Nuxt pages, simply use composables directly:

<script setup lang="ts">
// These are auto-imported by @vueuse/nuxt
const { x, y } = useMouse()
const isDark = useDark()
const counter = useStorage('counter', 0)
</script>

SSR-Safe Composables

The integration includes SSR-safe versions of browser APIs, ensuring your Nuxt applications work correctly during server-side rendering without hydration mismatches:

import { useWindowSize } from '#imports'

// Safe to use in SSR - returns null or default values during SSR
const { width, height } = useWindowSize()

For Nuxt projects using server-side rendering, the automatic import system works with tree-shaking to ensure you never bundle unused composables, even when you use the auto-import feature extensively.

Performance Optimization with VueUse

Tree-Shaking

One of VueUse's most important features is its tree-shakeable architecture. Each composable is exported as a separate function, so bundlers like Vite or Webpack can eliminate unused code from your final bundle:

// Only useMouse ends up in your bundle
import { useMouse } from '@vueuse/core'

This means adding VueUse to your project doesn't automatically increase bundle size by 200+ composables--only the composables you actually import and use contribute to the final bundle. For high-performance web applications, this optimization is essential for maintaining fast load times and smooth user experiences.

Lazy Loading

VueUse composables can be combined with Vue's async components and Nuxt's lazy loading for optimal performance:

import { defineAsyncComponent } from 'vue'
import { useIntersectionObserver } from '@vueuse/core'

const HeavyComponent = defineAsyncComponent(() =>
 import('./HeavyComponent.vue')
)

const target = ref(null)
const isVisible = useIntersectionObserver(target, ([entry]) => {
 return entry.isIntersecting
})

// Only load when target becomes visible
<HeavyComponent v-if="isVisible.value" ref="target" />

Best Practices

  • Let VueUse handle automatic cleanup on component unmount
  • Use TypeScript for full type inference
  • Combine composables for sophisticated patterns
  • Leverage auto-imports in Nuxt for cleaner code

VueUse composables automatically handle cleanup when components unmount, preventing memory leaks in your applications.

Building Common Features with VueUse

Infinite Scroll

Infinite scroll is a common requirement that VueUse makes straightforward:

import { useInfiniteScroll } from '@vueuse/core'

const el = ref<HTMLElement | null>(null)
const data = ref<Array<any>>([])

const loadMore = async () => {
 const newItems = await fetchItems(data.value.length)
 data.value.push(...newItems)
}

useInfiniteScroll(el, loadMore, { distance: 10 })

Toast Notifications

VueUse can power a reusable toast notification system:

import { useArrayFindLast } from '@vueuse/core'

const toasts = ref<Array<{id: number, message: string, type: string}>>([])

const addToast = (message: string, type = 'info') => {
 const id = Date.now()
 toasts.value.push({ id, message, type })

 // Auto-remove after 3 seconds
 setTimeout(() => {
 toasts.value = toasts.value.filter(t => t.id !== id)
 }, 3000)
}

// Find most recent toast of a specific type
const latestError = useArrayFindLast(toasts, t => t.type === 'error')

Form Validation Feedback

Combine VueUse composables for responsive form validation:

import { useDebounceFn, useStorage } from '@vueuse/core'

const email = ref('')
const emailError = ref('')

const checkEmailAvailability = useDebounceFn(async (email) => {
 const response = await fetch(`/api/check-email?email=${email}`)
 const { available } = await response.json()
 emailError.value = available ? '' : 'Email already registered'
}, 500)

watch(email, (newEmail) => {
 if (newEmail.includes('@')) {
 checkEmailAvailability(newEmail)
 }
})

Network Status

The useOnline composable detects network connectivity changes:

import { useOnline } from '@vueuse/core'

const isOnline = useOnline()

// Show offline indicator when disconnected
watch(isOnline, (online) => {
 if (!online) {
 showOfflineNotification()
 }
})

Frequently Asked Questions

Ready to Build Better Vue Applications?

Our team specializes in modern Vue.js and Nuxt.js development. Let us help you leverage VueUse and other modern tools to build performant, maintainable applications.

Sources

  1. VueUse Official Site - Primary documentation with 200+ composables for Vue 3
  2. VueUse GitHub Repository - Open source codebase with 16k+ stars
  3. Mastering Nuxt: 15 Must-Have Nuxt Modules - Nuxt integration details
  4. Nuxt Documentation - Composables - Nuxt composables directory structure