packages/core/useMagicKeys/index.md
Reactive keys pressed state, with magical keys combination support.
import { useMagicKeys } from '@vueuse/core'
const { shift, space, a /* keys you want to monitor */ } = useMagicKeys()
watch(space, (v) => {
if (v)
console.log('space has been pressed')
})
watchEffect(() => {
if (shift.value && a.value)
console.log('Shift + A have been pressed')
})
::: tip NOTE
If you're using TypeScript with noUncheckedIndexedAccess enabled in your tsconfig.json (or using Nuxt which enables it by default), the destructured keys will have the type ComputedRef<boolean> | undefined.
The noUncheckedIndexedAccess TypeScript option adds undefined to any un-declared field accessed via index signatures. Since useMagicKeys() uses an index signature to allow accessing any key dynamically, TypeScript will treat destructured properties as potentially undefined for type safety.
You'll need to use optional chaining or wrap with a getter function:
const { shift, space, a } = useMagicKeys()
watch(
() => space?.value,
(v) => {
if (v)
console.log('space has been pressed')
},
)
watchEffect(() => {
if (shift?.value && a?.value)
console.log('Shift + A have been pressed')
})
Check the TypeScript documentation for more details about noUncheckedIndexedAccess.
:::
Check out all the possible keycodes.
You can magically use combinations (shortcuts/hotkeys) by connecting keys with + or _.
import { useMagicKeys } from '@vueuse/core'
const keys = useMagicKeys()
const shiftCtrlA = keys['Shift+Ctrl+A']
watch(shiftCtrlA, (v) => {
if (v)
console.log('Shift + Ctrl + A have been pressed')
})
import { useMagicKeys } from '@vueuse/core'
const { Ctrl_A_B, space, alt_s /* ... */ } = useMagicKeys()
watch(Ctrl_A_B, (v) => {
if (v)
console.log('Control+A+B have been pressed')
})
You can also use whenever function to make it shorter
import { useMagicKeys, whenever } from '@vueuse/core'
const keys = useMagicKeys()
whenever(keys.shift_space, () => {
console.log('Shift+Space have been pressed')
})
A special property current is provided to representing all the keys been pressed currently.
import { useMagicKeys, whenever } from '@vueuse/core'
const { current } = useMagicKeys()
console.log(current) // Set { 'control', 'a' }
whenever(
() => current.has('a') && !current.has('b'),
() => console.log('A is pressed but not B'),
)
import { useMagicKeys, whenever } from '@vueuse/core'
const { shift_cool } = useMagicKeys({
aliasMap: {
cool: 'space',
},
})
whenever(shift_cool, () => console.log('Shift + Space have been pressed'))
By default, we have some preconfigured alias for common practices.
You might have some <input /> elements in your apps, and you don't want to trigger the magic keys handling when users focused on those inputs. There is an example of using useActiveElement and logicAnd to do that.
import { useActiveElement, useMagicKeys, whenever } from '@vueuse/core'
import { logicAnd } from '@vueuse/math'
const activeElement = useActiveElement()
const notUsingInput = computed(() =>
activeElement.value?.tagName !== 'INPUT'
&& activeElement.value?.tagName !== 'TEXTAREA',)
const { tab } = useMagicKeys()
whenever(logicAnd(tab, notUsingInput), () => {
console.log('Tab has been pressed outside of inputs!')
})
import { useMagicKeys, whenever } from '@vueuse/core'
const { ctrl_s } = useMagicKeys({
passive: false,
onEventFired(e) {
if (e.ctrlKey && e.key === 's' && e.type === 'keydown')
e.preventDefault()
},
})
whenever(ctrl_s, () => console.log('Ctrl+S have been pressed'))
⚠️ This usage is NOT recommended, please use with caution.
By default, the values of useMagicKeys() are Ref<boolean>. If you want to use the object in the template, you can set it to reactive mode.
import { useMagicKeys } from '@vueuse/core'
// ---cut---
const keys = useMagicKeys({ reactive: true })
<template>
<div v-if="keys.shift">
You are holding the Shift key!
</div>
</template>