VueUse
200+ Composables für produktive Vue-Entwicklung
Was ist VueUse?
VueUse ist eine Sammlung von über 200 sofort einsetzbaren Composition-API-Utilities (sogenannten Composables) für Vue 3. Statt das Rad jedes Mal neu zu erfinden, greifst du auf getestete, typsichere Funktionen zu — von Browser-APIs über Sensoren bis hin zu State-Helfern.
Die Bibliothek ist tree-shakable: Du importierst nur, was du brauchst, und der Rest wird beim Build entfernt. Jedes Composable ist eine einzelne Funktion, die reaktive Refs zurückgibt — perfekt für die Composition API.
Rails-Vergleich: Gems vs. Composables
In Rails installierst du Gems wie devise, pundit oder pagy, um wiederkehrende Aufgaben zu lösen. VueUse ist das Vue-Pendant — eine kuratierte Sammlung kleiner, fokussierter Bausteine. Der Unterschied: Composables sind keine Klassen oder Module, sondern Funktionen, die du direkt im setup() aufrufst und die reaktive Daten zurückgeben.
Installation und Einrichtung
# Installation
npm install @vueuse/core
# Optional: Integrations (Firebase, RxJS, etc.)
npm install @vueuse/integrationsNach der Installation importierst du einzelne Composables direkt — kein Plugin, keine globale Registrierung nötig:
<script setup>
import { useMouse, useLocalStorage } from '@vueuse/core'
const { x, y } = useMouse()
const name = useLocalStorage('user-name', 'Gast')
</script>
<template>
<p>Maus: {{ x }}, {{ y }}</p>
<input v-model="name" />
</template>Die 15 nützlichsten Composables
1. useMouse — Mausposition
Liefert die aktuelle Mausposition als reaktive Refs.
<script setup>
import { useMouse } from '@vueuse/core'
const { x, y, sourceType } = useMouse()
// x, y = reaktive Refs mit Pixelwerten
// sourceType = 'mouse' | 'touch'
</script>
<template>
<p>Position: {{ x }}, {{ y }} ({{ sourceType }})</p>
</template>2. useLocalStorage — Persistenter State
Synchronisiert eine Ref automatisch mit localStorage. Änderungen überleben Seiten-Reloads.
import { useLocalStorage } from '@vueuse/core'
// Zweiter Parameter = Standardwert
const theme = useLocalStorage('app-theme', 'light')
const user = useLocalStorage('user-prefs', { lang: 'de', fontSize: 16 })
// Schreiben aktualisiert automatisch localStorage
theme.value = 'dark'
user.value.fontSize = 18Rails-Vergleich
Das entspricht cookies.permanent oder Rails.cache.fetch — nur clientseitig und reaktiv.
3. useDark — Dark Mode
Erkennt und toggelt den Dark Mode mit einem einzigen Aufruf.
import { useDark, useToggle } from '@vueuse/core'
const isDark = useDark() // reaktive Ref<boolean>
const toggleDark = useToggle(isDark) // Toggle-Funktion
// Setzt automatisch class="dark" auf <html>4. useClipboard — Zwischenablage
Kopiert Text in die Zwischenablage und zeigt den aktuellen Inhalt an.
<script setup>
import { useClipboard } from '@vueuse/core'
const { text, copy, copied, isSupported } = useClipboard()
</script>
<template>
<button @click="copy('Hallo Welt!')" :disabled="!isSupported">
{{ copied ? '✅ Kopiert!' : '📋 Kopieren' }}
</button>
<p v-if="text">Zwischenablage: {{ text }}</p>
</template>5. useWindowSize — Fenstergröße
Reaktive Fensterdimensionen — ideal für responsive Logik im Script.
import { useWindowSize } from '@vueuse/core'
const { width, height } = useWindowSize()
// Reaktiv — aktualisiert sich bei Resize automatisch
const isMobile = computed(() => width.value < 768)6. useFetch — HTTP-Requests
Einfacher Fetch-Wrapper mit reaktivem Zustand für Daten, Fehler und Ladestatus.
<script setup>
import { useFetch } from '@vueuse/core'
const { data, error, isFetching } = useFetch('/api/users')
.get()
.json()
</script>
<template>
<p v-if="isFetching">Lade...</p>
<p v-else-if="error">Fehler: {{ error }}</p>
<ul v-else>
<li v-for="user in data" :key="user.id">{{ user.name }}</li>
</ul>
</template>Tipp
Für komplexere Server-State-Szenarien (Caching, Mutations, Invalidierung) empfiehlt sich Vue Query — siehe nächste Lektion.
7. useDebounce — Entprellen
Verzögert die Aktualisierung eines Werts, bis keine Änderungen mehr kommen.
import { useDebounce } from '@vueuse/core'
const search = ref('')
const debouncedSearch = useDebounce(search, 500)
// debouncedSearch aktualisiert sich erst 500ms
// nach der letzten Änderung von search
watch(debouncedSearch, (val) => {
fetchResults(val) // API-Call erst nach Tipp-Pause
})8. useThrottleFn — Drosseln
Führt eine Funktion höchstens alle n Millisekunden aus.
import { useThrottleFn } from '@vueuse/core'
const savePosition = useThrottleFn((x: number, y: number) => {
console.log('Position gespeichert:', x, y)
}, 1000)
// Wird höchstens 1× pro Sekunde ausgeführt,
// egal wie oft aufgerufen9. useIntersectionObserver — Sichtbarkeit
Erkennt, ob ein Element im Viewport sichtbar ist — perfekt für Lazy Loading.
<script setup>
import { useIntersectionObserver } from '@vueuse/core'
const target = ref<HTMLElement | null>(null)
const isVisible = ref(false)
useIntersectionObserver(target, ([{ isIntersecting }]) => {
isVisible.value = isIntersecting
})
</script>
<template>
<div ref="target">
<img v-if="isVisible" src="/grosses-bild.jpg" alt="Lazy" />
<div v-else class="placeholder">Wird geladen...</div>
</div>
</template>10. useEventListener — Event-Handling
Registriert Events, die beim Unmount automatisch entfernt werden — kein manuelles removeEventListener nötig.
import { useEventListener } from '@vueuse/core'
// Wird automatisch beim Unmount entfernt!
useEventListener(window, 'keydown', (e: KeyboardEvent) => {
if (e.key === 'Escape') closeModal()
})
// Auch auf Elemente anwendbar:
const button = ref<HTMLButtonElement | null>(null)
useEventListener(button, 'click', () => doSomething())11. useMediaQuery — Media Queries
Reaktive CSS Media Queries im JavaScript.
import { useMediaQuery } from '@vueuse/core'
const isLargeScreen = useMediaQuery('(min-width: 1024px)')
const prefersDark = useMediaQuery('(prefers-color-scheme: dark)')
const isRetina = useMediaQuery('(min-resolution: 2dppx)')
// Reactive — aktualisiert sich bei Änderung12. onClickOutside — Klick außerhalb
Erkennt Klicks außerhalb eines Elements — ideal für Dropdowns und Modals.
<script setup>
import { onClickOutside } from '@vueuse/core'
const dropdown = ref<HTMLElement | null>(null)
const isOpen = ref(false)
onClickOutside(dropdown, () => {
isOpen.value = false
})
</script>
<template>
<div ref="dropdown" class="dropdown">
<button @click="isOpen = !isOpen">Menü</button>
<ul v-if="isOpen">
<li>Option A</li>
<li>Option B</li>
</ul>
</div>
</template>13. useScroll — Scroll-Position
Verfolgt die Scroll-Position eines Elements oder des Fensters.
import { useScroll } from '@vueuse/core'
// Fenster-Scroll
const { x, y, isScrolling, arrivedState } = useScroll(window)
// arrivedState = { top, bottom, left, right }
const showBackToTop = computed(() => y.value > 500)
const isAtBottom = computed(() => arrivedState.bottom)14. useColorMode — Farbmodus-Verwaltung
Erweiterte Variante von useDark — unterstützt mehrere Modi (light, dark, sepia, etc.) mit automatischer Persistierung.
import { useColorMode } from '@vueuse/core'
const mode = useColorMode({
modes: {
light: 'light',
dark: 'dark',
sepia: 'sepia',
},
})
// mode.value = 'light' | 'dark' | 'sepia'
mode.value = 'sepia' // Wechselt Modus + persistiert15. useBreakpoints — Responsive Breakpoints
Definiere Breakpoints und reagiere reaktiv auf Größenänderungen.
import { useBreakpoints } from '@vueuse/core'
const breakpoints = useBreakpoints({
sm: 640,
md: 768,
lg: 1024,
xl: 1280,
})
const isMobile = breakpoints.smaller('md') // < 768px
const isTablet = breakpoints.between('md', 'lg') // 768–1024px
const isDesktop = breakpoints.greater('lg') // > 1024px
const current = breakpoints.current() // ['sm'] | ['md'] | ...Live-Demo: Mausposition & Fenstergröße
Diese Demo kombiniert useMouse und useWindowSize, um Echtzeit-Informationen anzuzeigen. Bewege die Maus und ändere die Fenstergröße!
🖱️ Mausposition
x: 0 / y: 0
📐 Fenstergröße
0 × 0px
📱 Gerät
Mobil
<script setup>
import { useMouse, useWindowSize } from '@vueuse/core'
const { x, y } = useMouse()
const { width, height } = useWindowSize()
const deviceType = computed(() => {
if (width.value < 640) return 'Mobil'
if (width.value < 1024) return 'Tablet'
return 'Desktop'
})
</script>
<template>
<div class="grid grid-cols-2 gap-4">
<div class="info-card">
<p>🖱️ Mausposition</p>
<p>x: {{ x }} / y: {{ y }}</p>
</div>
<div class="info-card">
<p>📐 Fenstergröße</p>
<p>{{ width }} × {{ height }}px</p>
</div>
</div>
<p>📱 Gerät: {{ deviceType }}</p>
</template>Zusammenfassung
Das Wichtigste
- VueUse bietet 200+ fertige Composables für alltägliche Aufgaben.
- Alles ist tree-shakable — importiere nur, was du brauchst.
- Jedes Composable gibt reaktive Refs zurück.
- Events und Observer werden beim Unmount automatisch aufgeräumt.
- Besuche vueuse.org für die vollständige Dokumentation.