
Vueuse Functions
- 16 installs
- 377 repo stars
- Updated July 30, 2026
- vueuse/vueuse-skills
Helps with ai & agent building tasks.
About
vueuse-functions is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- vueuse-functions
- AI & Agent Building
- AI-coding skill
Vueuse Functions by the numbers
- 16 all-time installs (skills.sh)
- +5 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #11,062 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Jul 31, 2026 (Skillselion catalog sync)
npx skills add https://github.com/vueuse/vueuse-skills --skill vueuse-functionsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 16 |
|---|---|
| repo stars | ★ 377 |
| Last updated | July 30, 2026 |
| Repository | vueuse/vueuse-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
computedAsync
Computed for async functions.
Usage
import { computedAsync } from '@vueuse/core'
import { shallowRef } from 'vue'
const name = shallowRef('jack')
const userInfo = computedAsync(
async () => {
return await mockLookUp(name.value)
},
null, // initial state
)Evaluation State
Pass a ref to track if the async function is currently evaluating.
import { computedAsync } from '@vueuse/core'
import { shallowRef } from 'vue'
const evaluating = shallowRef(false)
const userInfo = computedAsync(
async () => { /* your logic */ },
null,
evaluating, // can also be passed via options: { evaluating }
)onCancel
When the computed source changes before the previous async function resolves, you may want to cancel the previous one. Here is an example showing how to incorporate with the fetch API.
import { computedAsync } from '@vueuse/core'
import { shallowRef } from 'vue'
const packageName = shallowRef('@vueuse/core')
const downloads = computedAsync(async (onCancel) => {
const abortController = new AbortController()
onCancel(() => abortController.abort())
return await fetch(
`https://api.npmjs.org/downloads/point/last-week/${packageName.value}`,
{ signal: abortController.signal },
)
.then(response => response.ok ? response.json() : { downloads: '—' })
.then(result => result.downloads)
}, 0)Lazy
By default, computedAsync will start resolving immediately on creation. Specify lazy: true to make it start resolving on the first access.
import { computedAsync } from '@vueuse/core'
import { shallowRef } from 'vue'
const evaluating = shallowRef(false)
const userInfo = computedAsync(
async () => { /* your logic */ },
null,
{ lazy: true, evaluating },
)Error Handling
Use the onError callback to handle errors from the async function.
import { computedAsync } from '@vueuse/core'
import { shallowRef } from 'vue'
const name = shallowRef('jack')
const userInfo = computedAsync(
async () => {
return await mockLookUp(name.value)
},
null,
{
onError(e) {
console.error('Failed to fetch user info', e)
},
},
)Shallow Ref
By default, computedAsync uses shallowRef internally. Set shallow: false to use a deep ref instead.
import { computedAsync } from '@vueuse/core'
import { shallowRef } from 'vue'
const name = shallowRef('jack')
const userInfo = computedAsync(
async () => {
return await fetchNestedData(name.value)
},
null,
{ shallow: false }, // enables deep reactivity
)Caveats
- Just like Vue's built-in
computedfunction,computedAsyncdoes dependency tracking and is automatically re-evaluated when dependencies change. Note however that only dependencies referenced in the first call stack are considered for this. In other words: Dependencies that are accessed asynchronously will not trigger re-evaluation of the async computed value.
- As opposed to Vue's built-in
computedfunction, re-evaluation of the async computed value is triggered whenever dependencies are changing, regardless of whether its result is currently being tracked or not.
Type Declarations
/**
* Handle overlapping async evaluations.
*
* @param cancelCallback The provided callback is invoked when a re-evaluation of the computed value is triggered before the previous one finished
*/
export type AsyncComputedOnCancel = (cancelCallback: Fn) => void
export interface AsyncComputedOptions<
Lazy = boolean,
> extends ConfigurableFlushSync {
/**
* Should value be evaluated lazily
*
* @default false
*/
lazy?: Lazy
/**
* Ref passed to receive the updated of async evaluation
*/
evaluating?: Ref<boolean>
/**
* Use shallowRef
*
* @default true
*/
shallow?: boolean
/**
* Callback when error is caught.
*/
onError?: (e: unknown) => void
}
/**
* Create an asynchronous computed dependency.
*
* @see https://vueuse.org/computedAsync
* @param evaluationCallback The promise-returning callback which generates the computed value
* @param initialState The initial state, used until the first evaluation finishes
* @param optionsOrRef Additional options or a ref passed to receive the updates of the async evaluation
*/
export declare function computedAsync<T>(
evaluationCallback: (onCancel: AsyncComputedOnCancel) => T | Promise<T>,
initialState: T,
optionsOrRef: AsyncComputedOptions<true>,
): ComputedRef<T>
export declare function computedAsync<T>(
evaluationCallback: (onCancel: AsyncComputedOnCancel) => T | Promise<T>,
initialState: undefined,
optionsOrRef: AsyncComputedOptions<true>,
): ComputedRef<T | undefined>
export declare function computedAsync<T>(
evaluationCallback: (onCancel: AsyncComputedOnCancel) => T | Promise<T>,
initialState: T,
optionsOrRef?: Ref<boolean> | AsyncComputedOptions,
): Ref<T>
export declare function computedAsync<T>(
evaluationCallback: (onCancel: AsyncComputedOnCancel) => T | Promise<T>,
initialState?: undefined,
optionsOrRef?: Ref<boolean> | AsyncComputedOptions,
): Ref<T | undefined>
/** @deprecated use `computedAsync` instead */
export declare const asyncComputed: typeof computedAsynccomputedEager
Eager computed without lazy evaluation.
::: info This function will be removed in future version. :::
::: tip Note💡: If you are using Vue 3.4+, you can use computed right away, you no longer need this function. In Vue 3.4+, if the computed new value does not change, computed, effect, watch, watchEffect, render dependencies will not be triggered. See: https://github.com/vuejs/core/pull/5912 :::
Learn more at Vue: When a computed property can be the wrong tool.
- Use
computed()when you have a complex calculation going on, which can actually profit from caching and lazy evaluation and should only be (re-)calculated if really necessary. - Use
computedEager()when you have a simple operation, with a rarely changing return value – often a boolean.
Usage
import { computedEager } from '@vueuse/core'
const todos = ref([])
const hasOpenTodos = computedEager(() => !!todos.length)
console.log(hasOpenTodos.value) // false
toTodos.value.push({ title: 'Learn Vue' })
console.log(hasOpenTodos.value) // trueType Declarations
export type ComputedEagerOptions = WatchOptionsBase
export type ComputedEagerReturn<T = any> = Readonly<ShallowRef<T>>
/**
*
* @deprecated This function will be removed in future version.
*
* Note: If you are using Vue 3.4+, you can straight use computed instead.
* Because in Vue 3.4+, if computed new value does not change,
* computed, effect, watch, watchEffect, render dependencies will not be triggered.
* refer: https://github.com/vuejs/core/pull/5912
*
* @param fn effect function
* @param options WatchOptionsBase
* @returns readonly shallowRef
*/
export declare function computedEager<T>(
fn: () => T,
options?: ComputedEagerOptions,
): ComputedEagerReturn<T>
/** @deprecated use `computedEager` instead */
export declare const eagerComputed: typeof computedEagercomputedInject
Combine computed and inject. Useful for creating a computed property based on an injected value.
Usage
In Provider Component
```ts twoslash include main import type { InjectionKey, Ref } from 'vue' import { provide, ref } from 'vue'
interface Item { key: number value: string }
export const ArrayKey: InjectionKey<Ref<Item[]>> = Symbol('symbol-key')
const array = ref([{ key: 1, value: '1' }, { key: 2, value: '2' }, { key: 3, value: '3' }])
provide(ArrayKey, array)
In Receiver Component
// @filename: provider.ts // @include: main // ---cut--- import { computedInject } from '@vueuse/core'
import { ArrayKey } from './provider'
const computedArray = computedInject(ArrayKey, (source) => { const arr = [...source.value] arr.unshift({ key: 0, value: 'all' }) return arr })
### Default Value
You can provide a default value that will be used if the injection key is not provided by a parent component.
import { computedInject } from '@vueuse/core'
const computedArray = computedInject( ArrayKey, (source) => { return source.value.map(item => item.value) }, ref([]), // default source value )
### Factory Default
Pass `true` as the fourth argument to treat the default value as a factory function.
import { computedInject } from '@vueuse/core'
const computedArray = computedInject( ArrayKey, (source) => { return source.value.map(item => item.value) }, () => ref([]), // factory function for default true, // treat default as factory )
### Writable Computed
You can also create a writable computed property by passing an object with `get` and `set` functions.
import { computedInject } from '@vueuse/core'
const computedArray = computedInject(ArrayKey, { get(source) { return source.value.map(item => item.value) }, set(value) { // handle setting the value console.log('Setting value:', value) }, })
## Type Declarations
export type ComputedInjectGetter<T, K> = ( source: T | undefined, oldValue?: K, ) => K export type ComputedInjectGetterWithDefault<T, K> = ( source: T, oldValue?: K, ) => K export type ComputedInjectSetter<T> = (v: T) => void export interface WritableComputedInjectOptions<T, K> { get: ComputedInjectGetter<T, K> set: ComputedInjectSetter<K> } export interface WritableComputedInjectOptionsWithDefault<T, K> { get: ComputedInjectGetterWithDefault<T, K> set: ComputedInjectSetter<K> } export declare function computedInject<T, K = any>( key: InjectionKey<T> | string, getter: ComputedInjectGetter<T, K>, ): ComputedRef<K | undefined> export declare function computedInject<T, K = any>( key: InjectionKey<T> | string, options: WritableComputedInjectOptions<T, K>, ): ComputedRef<K | undefined> export declare function computedInject<T, K = any>( key: InjectionKey<T> | string, getter: ComputedInjectGetterWithDefault<T, K>, defaultSource: T, treatDefaultAsFactory?: false, ): ComputedRef<K> export declare function computedInject<T, K = any>( key: InjectionKey<T> | string, options: WritableComputedInjectOptionsWithDefault<T, K>, defaultSource: T | (() => T), treatDefaultAsFactory: true, ): ComputedRef<K>
computedWithControl
Explicitly define the dependencies of computed.
Usage
```ts twoslash include main import { computedWithControl } from '@vueuse/core'
const source = ref('foo') const counter = ref(0)
const computedRef = computedWithControl( () => source.value, // watch source, same as watch () => counter.value, // computed getter, same as computed )
With this, the changes of `counter` won't trigger `computedRef` to update but the `source` ref does.
// @include: main // ---cut--- console.log(computedRef.value) // 0
counter.value += 1
console.log(computedRef.value) // 0
source.value = 'bar'
console.log(computedRef.value) // 1
### Manual Triggering
You can also manually trigger the update of the computed by:
// @include: main // ---cut--- const computedRef = computedWithControl( () => source.value, () => counter.value, )
computedRef.trigger()
### Deep Watch
Unlike `computed`, `computedWithControl` is shallow by default.
You can specify the same options as `watch` to control the behavior:
const source = ref({ name: 'foo' })
const computedRef = computedWithControl( source, () => counter.value, { deep: true }, )
## Type Declarations
export interface ComputedWithControlRefExtra { /**
- Force update the computed value.
/ trigger: () => void } export interface ComputedRefWithControl<T> extends ComputedRef<T>, ComputedWithControlRefExtra {} export interface WritableComputedRefWithControl<T> extends WritableComputedRef<T>, ComputedWithControlRefExtra {} export type ComputedWithControlRef<T = any> = | ComputedRefWithControl<T> | WritableComputedRefWithControl<T> export declare function computedWithControl<T>( source: WatchSource | MultiWatchSources, fn: ComputedGetter<T>, options?: WatchOptions, ): ComputedRefWithControl<T> export declare function computedWithControl<T>( source: WatchSource | MultiWatchSources, fn: WritableComputedOptions<T>, options?: WatchOptions, ): WritableComputedRefWithControl<T> / @deprecated use `computedWithControl` instead / export declare const controlledComputed: typeof computedWithControl
createDisposableDirective
Utility for authoring disposable directives. Reactive effects created within mounted directive hook will be tracked and automatically disposed when directive is unmounted.
Usage
Creating a directive that uses createDisposableDirective
import { useMouse } from '@vueuse/core'
import { createDisposableDirective } from '@vueuse/shared'
export const VDirective = createDisposableDirective({
mounted(el, binding) {
const value = binding.value
if (typeof value === 'function') {
// `useMouse` event listener will be removed automatically when directive is unmounted
const { x, y } = useMouse()
watch(x, val => value(val))
}
}
})Type Declarations
type originDirective<H, V, A> =
| FunctionDirective<H, V, string, A>
| ObjectDirective<H, V, string, A>
/**
* Utility for authoring disposable directives. Reactive effects created within `mounted` directive hook will be tracked and automatically disposed when directive is unmounted.
*
* @see https://vueuse.org/createDisposableDirective
*
* @__NO_SIDE_EFFECTS__
*/
export declare function createDisposableDirective<
H extends HTMLElement,
V,
A = any,
>(origin?: originDirective<H, V, A>): originDirective<H, V, A>createEventHook
Utility for creating event hooks
Usage
Creating a function that uses createEventHook
import { createEventHook } from '@vueuse/core'
export function useMyFetch(url) {
const fetchResult = createEventHook<Response>()
const fetchError = createEventHook<any>()
fetch(url)
.then(result => fetchResult.trigger(result))
.catch(error => fetchError.trigger(error.message))
return {
onResult: fetchResult.on,
onError: fetchError.on,
}
}Using a function that uses createEventHook
<script setup lang="ts">
import { useMyFetch } from './my-fetch-function'
const { onResult, onError } = useMyFetch('my api url')
onResult((result) => {
console.log(result)
})
onError((error) => {
console.error(error)
})
</script>Type Declarations
/**
* The source code for this function was inspired by vue-apollo's `useEventHook` util
* https://github.com/vuejs/vue-apollo/blob/v4/packages/vue-apollo-composable/src/util/useEventHook.ts
*/
type Callback<T> =
IsAny<T> extends true
? (...param: any) => void
: [T] extends [void]
? (...param: unknown[]) => void
: [T] extends [any[]]
? (...param: T) => void
: (...param: [T, ...unknown[]]) => void
export type EventHookOn<T = any> = (fn: Callback<T>) => {
off: () => void
}
export type EventHookOff<T = any> = (fn: Callback<T>) => void
export type EventHookTrigger<T = any> = (
...param: Parameters<Callback<T>>
) => Promise<unknown[]>
export interface EventHook<T = any> {
on: EventHookOn<T>
off: EventHookOff<T>
trigger: EventHookTrigger<T>
clear: () => void
}
export type EventHookReturn<T> = EventHook<T>
/**
* Utility for creating event hooks
*
* @see https://vueuse.org/createEventHook
*
* @__NO_SIDE_EFFECTS__
*/
export declare function createEventHook<T = any>(): EventHookReturn<T>createGenericProjection
Generic version of createProjection. Accepts a custom projector function to map arbitrary type of domains.
Refer to createProjection and useProjection
Type Declarations
export type ProjectorFunction<F, T> = (
input: F,
from: readonly [F, F],
to: readonly [T, T],
) => T
export type UseProjection<F, T> = (input: MaybeRefOrGetter<F>) => ComputedRef<T>
export declare function createGenericProjection<F = number, T = number>(
fromDomain: MaybeRefOrGetter<readonly [F, F]>,
toDomain: MaybeRefOrGetter<readonly [T, T]>,
projector: ProjectorFunction<F, T>,
): UseProjection<F, T>createGlobalState
Keep states in the global scope to be reusable across Vue instances.
Usage
Without Persistence (Store in Memory)
// store.ts
import { createGlobalState } from '@vueuse/core'
import { shallowRef } from 'vue'
export const useGlobalState = createGlobalState(
() => {
const count = shallowRef(0)
return { count }
}
)A bigger example:
// store.ts
import { createGlobalState } from '@vueuse/core'
import { computed, shallowRef } from 'vue'
export const useGlobalState = createGlobalState(
() => {
// state
const count = shallowRef(0)
// getters
const doubleCount = computed(() => count.value * 2)
// actions
function increment() {
count.value++
}
return { count, doubleCount, increment }
}
)With Persistence
Store in localStorage with useStorage:
```ts twoslash include store // store.ts import { createGlobalState, useStorage } from '@vueuse/core'
export const useGlobalState = createGlobalState( () => useStorage('vueuse-local-storage', 'initialValue'), )
// @filename: store.ts // @include: store // ---cut--- // component.ts import { useGlobalState } from './store'
export default defineComponent({ setup() { const state = useGlobalState() return { state } }, })
## Type Declarations
export type CreateGlobalStateReturn<Fn extends AnyFn = AnyFn> = Fn /**
- Keep states in the global scope to be reusable across Vue instances.
*
- @see https://vueuse.org/createGlobalState
- @param stateFactory A factory function to create the state
*
- @__NO_SIDE_EFFECTS__
*/ export declare function createGlobalState<Fn extends AnyFn>( stateFactory: Fn, ): CreateGlobalStateReturn<Fn>
createInjectionState
Create global state that can be injected into components.
Usage
```ts twoslash include useCounterStore // useCounterStore.ts import { createInjectionState } from '@vueuse/core' import { computed, shallowRef } from 'vue'
const [useProvideCounterStore, useCounterStore] = createInjectionState((initialValue: number) => { // state const count = shallowRef(initialValue)
// getters const double = computed(() => count.value * 2)
// actions function increment() { count.value++ }
return { count, double, increment } })
export { useProvideCounterStore }
// If you want to hide useCounterStore and wrap it in default value logic or throw error logic, please don't export useCounterStore export { useCounterStore }
export function useCounterStoreWithDefaultValue() { return useCounterStore() ?? { count: shallowRef(0), double: shallowRef(0), increment: () => {}, } }
export function useCounterStoreOrThrow() { const counterStore = useCounterStore() if (counterStore == null) throw new Error('Please call useProvideCounterStore on the appropriate parent component') return counterStore }
<!-- RootComponent.vue --> <script setup lang="ts"> // @filename: useCounterStore.ts // @include: useCounterStore // ---cut--- import { useProvideCounterStore } from './useCounterStore'
useProvideCounterStore(0) </script>
<template> <div> <slot /> </div> </template>
<!-- CountComponent.vue --> <script setup lang="ts"> // @filename: useCounterStore.ts // @include: useCounterStore // ---cut--- import { useCounterStore } from './useCounterStore'
// use non-null assertion operator to ignore the case that store is not provided. const { count, double } = useCounterStore()! // if you want to allow component to working without providing store, you can use follow code instead: // const { count, double } = useCounterStore() ?? { count: shallowRef(0), double: shallowRef(0) } // also, you can use another hook to provide default value // const { count, double } = useCounterStoreWithDefaultValue() // or throw error // const { count, double } = useCounterStoreOrThrow() </script>
<template> <ul> <li> count: {{ count }} </li> <li> double: {{ double }} </li> </ul> </template>
<!-- ButtonComponent.vue --> <script setup lang="ts"> // @filename: useCounterStore.ts // @include: useCounterStore // ---cut--- import { useCounterStore } from './useCounterStore'
// use non-null assertion operator to ignore the case that store is not provided. const { increment } = useCounterStore()! </script>
<template> <button @click="increment"> + </button> </template>
## Provide a custom InjectionKey
// useCounterStore.ts import { createInjectionState } from '@vueuse/core' import { computed, shallowRef } from 'vue'
// custom injectionKey const CounterStoreKey = 'counter-store'
const [useProvideCounterStore, useCounterStore] = createInjectionState((initialValue: number) => { // state const count = shallowRef(initialValue)
// getters const double = computed(() => count.value * 2)
// actions function increment() { count.value++ }
return { count, double, increment } }, { injectionKey: CounterStoreKey })
## Provide a custom default value
// useCounterStore.ts import { createInjectionState } from '@vueuse/core' import { computed, shallowRef } from 'vue'
// useCounterStore does not return undefined when defaultValue is specified const [useProvideCounterStore, useCounterStore] = createInjectionState((initialValue: number) => { // state const count = shallowRef(initialValue)
// getters const double = computed(() => count.value * 2)
// actions function increment() { count.value++ }
return { count, double, increment } }, { defaultValue: 0 })
## Type Declarations
export type CreateInjectionStateReturn< Arguments extends Array<any>, ProvideReturn, InjectReturn,
= Readonly<
[ /**
- Call this function in a provider component to create and provide the state.
*
- @param args Arguments passed to the composable
- @returns The state returned by the composable
/ useProvidingState: (...args: Arguments) => ProvideReturn, /*
- Call this function in a consumer component to inject the state.
*
- @returns The injected state, or
undefinedif not provided and no default value was set.
/ useInjectedState: () => InjectReturn, ] > export interface CreateInjectionStateOptions<Return> { /*
- Custom injectionKey for InjectionState
/ injectionKey?: string | InjectionKey<Return> /*
- Default value for the InjectionState
/ defaultValue?: Return } /*
- Create global state that can be injected into components.
*
- @see https://vueuse.org/createInjectionState
*
- @__NO_SIDE_EFFECTS__
*/ export declare function createInjectionState< Arguments extends Array<any>, Return, >( composable: (...args: Arguments) => Return, options: { defaultValue: Return } & CreateInjectionStateOptions<Return>, ): CreateInjectionStateReturn<Arguments, Return, Return> export declare function createInjectionState< Arguments extends Array<any>, Return, >( composable: (...args: Arguments) => Return, options?: CreateInjectionStateOptions<Return>, ): CreateInjectionStateReturn<Arguments, Return, Return | undefined>
createProjection
Reactive numeric projection from one domain to another.
Usage
import { createProjection } from '@vueuse/math'
const useProjector = createProjection([0, 10], [0, 100])
const input = ref(0)
const projected = useProjector(input) // projected.value === 0
input.value = 5 // projected.value === 50
input.value = 10 // projected.value === 100Type Declarations
export declare function createProjection(
fromDomain: MaybeRefOrGetter<readonly [number, number]>,
toDomain: MaybeRefOrGetter<readonly [number, number]>,
projector?: ProjectorFunction<number, number>,
): UseProjection<number, number>createRef
Returns a deepRef or shallowRef depending on the deep param.
Usage
import { createRef } from '@vueuse/core'
import { isShallow, ref } from 'vue'
const initialData = 1
const shallowData = createRef(initialData)
const deepData = createRef(initialData, true)
isShallow(shallowData) // true
isShallow(deepData) // falseType Declarations
export type CreateRefReturn<
T = any,
D extends boolean = false,
> = ShallowOrDeepRef<T, D>
export type ShallowOrDeepRef<
T = any,
D extends boolean = false,
> = D extends true ? Ref<T> : ShallowRef<T>
/**
* Returns a `deepRef` or `shallowRef` depending on the `deep` param.
*
* @example createRef(1) // ShallowRef<number>
* @example createRef(1, false) // ShallowRef<number>
* @example createRef(1, true) // Ref<number>
* @example createRef("string") // ShallowRef<string>
* @example createRef<"A"|"B">("A", true) // Ref<"A"|"B">
*
* @param value
* @param deep
* @returns the `deepRef` or `shallowRef`
*
* @__NO_SIDE_EFFECTS__
*/
export declare function createRef<T = any, D extends boolean = false>(
value: T,
deep?: D,
): CreateRefReturn<T, D>createReusableTemplate
Define and reuse template inside the component scope.
Motivation
It's common to have the need to reuse some part of the template. For example:
<template>
<dialog v-if="showInDialog">
<!-- something complex -->
</dialog>
<div v-else>
<!-- something complex -->
</div>
</template>We'd like to reuse our code as much as possible. So normally we might need to extract those duplicated parts into a component. However, in a separated component you lose the ability to access the local bindings. Defining props and emits for them can be tedious sometimes.
So this function is made to provide a way for defining and reusing templates inside the component scope.
Usage
In the previous example, we could refactor it to:
<script setup lang="ts">
import { createReusableTemplate } from '@vueuse/core'
const [DefineTemplate, ReuseTemplate] = createReusableTemplate()
</script>
<template>
<DefineTemplate>
<!-- something complex -->
</DefineTemplate>
<dialog v-if="showInDialog">
<ReuseTemplate />
</dialog>
<div v-else>
<ReuseTemplate />
</div>
</template><DefineTemplate>will register the template and renders nothing.<ReuseTemplate>will render the template provided by<DefineTemplate>.<DefineTemplate>must be used before<ReuseTemplate>.
Note: It's recommended to extract as separate components whenever possible. Abusing this function might lead to bad practices for your codebase.
Options API
When using with Options API, you will need to define createReusableTemplate outside of the component setup and pass to the components option in order to use them in the template.
<script>
import { createReusableTemplate } from '@vueuse/core'
import { defineComponent } from 'vue'
const [DefineTemplate, ReuseTemplate] = createReusableTemplate()
export default defineComponent({
components: {
DefineTemplate,
ReuseTemplate,
},
setup() {
// ...
},
})
</script>
<template>
<DefineTemplate v-slot="{ data, msg, anything }">
<div>{{ data }} passed from usage</div>
</DefineTemplate>
<ReuseTemplate :data="data" msg="The first usage" />
</template>Passing Data
You can also pass data to the template using slots:
- Use
v-slot="..."to access the data on<DefineTemplate> - Directly bind the data on
<ReuseTemplate>to pass them to the template
<script setup lang="ts">
import { createReusableTemplate } from '@vueuse/core'
const [DefineTemplate, ReuseTemplate] = createReusableTemplate()
</script>
<template>
<DefineTemplate v-slot="{ data, msg, anything }">
<div>{{ data }} passed from usage</div>
</DefineTemplate>
<ReuseTemplate :data="data" msg="The first usage" />
<ReuseTemplate :data="anotherData" msg="The second usage" />
<ReuseTemplate v-bind="{ data: something, msg: 'The third' }" />
</template>TypeScript Support
createReusableTemplate accepts a generic type to provide type support for the data passed to the template:
<script setup lang="ts">
import { createReusableTemplate } from '@vueuse/core'
// Comes with pair of `DefineTemplate` and `ReuseTemplate`
const [DefineFoo, ReuseFoo] = createReusableTemplate<{ msg: string }>()
// You can create multiple reusable templates
const [DefineBar, ReuseBar] = createReusableTemplate<{ items: string[] }>()
</script>
<template>
<DefineFoo v-slot="{ msg }">
<!-- `msg` is typed as `string` -->
<div>Hello {{ msg.toUpperCase() }}</div>
</DefineFoo>
<ReuseFoo msg="World" />
<!-- @ts-expect-error Type Error! -->
<ReuseFoo :msg="1" />
</template>Optionally, if you are not a fan of array destructuring, the following usages are also legal:
<script setup lang="ts">
import { createReusableTemplate } from '@vueuse/core'
const { define: DefineFoo, reuse: ReuseFoo } = createReusableTemplate<{
msg: string
}>()
</script>
<template>
<DefineFoo v-slot="{ msg }">
<div>Hello {{ msg.toUpperCase() }}</div>
</DefineFoo>
<ReuseFoo msg="World" />
</template><script setup lang="ts">
import { createReusableTemplate } from '@vueuse/core'
const TemplateFoo = createReusableTemplate<{ msg: string }>()
</script>
<template>
<TemplateFoo.define v-slot="{ msg }">
<div>Hello {{ msg.toUpperCase() }}</div>
</TemplateFoo.define>
<TemplateFoo.reuse msg="World" />
</template>::: warning Passing boolean props without v-bind is not supported. See the Caveats section for more details. :::
Props and Attributes
By default, all props and attributes passed to <ReuseTemplate> will be passed to the template. If you don't want certain props to be passed to the DOM, you need to define the runtime props:
import { createReusableTemplate } from '@vueuse/core'
const [DefineTemplate, ReuseTemplate] = createReusableTemplate({
props: {
msg: String,
enable: Boolean,
}
})If you don't want to pass any props to the template, you can pass the inheritAttrs option:
import { createReusableTemplate } from '@vueuse/core'
const [DefineTemplate, ReuseTemplate] = createReusableTemplate({
inheritAttrs: false,
})Passing Slots
It's also possible to pass slots back from <ReuseTemplate>. You can access the slots on <DefineTemplate> from $slots:
<script setup lang="ts">
import { createReusableTemplate } from '@vueuse/core'
const [DefineTemplate, ReuseTemplate] = createReusableTemplate()
</script>
<template>
<DefineTemplate v-slot="{ $slots, otherProp }">
<div some-layout>
<!-- To render the slot -->
<component :is="$slots.default" />
</div>
</DefineTemplate>
<ReuseTemplate>
<div>Some content</div>
</ReuseTemplate>
<ReuseTemplate>
<div>Another content</div>
</ReuseTemplate>
</template>Caveats
Boolean props
As opposed to Vue's behavior, props defined as boolean that were passed without v-bind or absent will be resolved into an empty string or undefined respectively:
<script setup lang="ts">
import { createReusableTemplate } from '@vueuse/core'
const [DefineTemplate, ReuseTemplate] = createReusableTemplate<{
value?: boolean
}>()
</script>
<template>
<DefineTemplate v-slot="{ value }">
{{ typeof value }}: {{ value }}
</DefineTemplate>
<ReuseTemplate :value="true" />
<!-- boolean: true -->
<ReuseTemplate :value="false" />
<!-- boolean: false -->
<ReuseTemplate value />
<!-- string: -->
<ReuseTemplate />
<!-- undefined: -->
</template>References
This function is migrated from vue-reuse-template.
Existing Vue discussions/issues about reusing template:
Alternative Approaches:
Type Declarations
type ObjectLiteralWithPotentialObjectLiterals = Record<
string,
Record<string, any> | undefined
>
type GenerateSlotsFromSlotMap<
T extends ObjectLiteralWithPotentialObjectLiterals,
> = {
[K in keyof T]: Slot<T[K]>
}
export type DefineTemplateComponent<
Bindings extends Record<string, any>,
MapSlotNameToSlotProps extends ObjectLiteralWithPotentialObjectLiterals,
> = DefineComponent & {
new (): {
$slots: {
default: (
_: Bindings & {
$slots: GenerateSlotsFromSlotMap<MapSlotNameToSlotProps>
},
) => any
}
}
}
export type ReuseTemplateComponent<
Bindings extends Record<string, any>,
MapSlotNameToSlotProps extends ObjectLiteralWithPotentialObjectLiterals,
> = DefineComponent<Bindings> & {
new (): {
$slots: GenerateSlotsFromSlotMap<MapSlotNameToSlotProps>
}
}
export type ReusableTemplatePair<
Bindings extends Record<string, any>,
MapSlotNameToSlotProps extends ObjectLiteralWithPotentialObjectLiterals,
> = [
DefineTemplateComponent<Bindings, MapSlotNameToSlotProps>,
ReuseTemplateComponent<Bindings, MapSlotNameToSlotProps>,
] & {
define: DefineTemplateComponent<Bindings, MapSlotNameToSlotProps>
reuse: ReuseTemplateComponent<Bindings, MapSlotNameToSlotProps>
}
export interface CreateReusableTemplateOptions<
Props extends Record<string, any>,
> {
/**
* Inherit attrs from reuse component.
*
* @default true
*/
inheritAttrs?: boolean
/**
* Name for the reuse component (useful for devtools).
*/
name?: string
/**
* Props definition for reuse component.
*/
props?: ComponentObjectPropsOptions<Props>
}
/**
* This function creates `define` and `reuse` components in pair,
* It also allow to pass a generic to bind with type.
*
* @see https://vueuse.org/createReusableTemplate
*
* @__NO_SIDE_EFFECTS__
*/
export declare function createReusableTemplate<
Bindings extends Record<string, any>,
MapSlotNameToSlotProps extends ObjectLiteralWithPotentialObjectLiterals =
Record<"default", undefined>,
>(
options?: CreateReusableTemplateOptions<Bindings>,
): ReusableTemplatePair<Bindings, MapSlotNameToSlotProps>createSharedComposable
Make a composable function usable with multiple Vue instances.
[!WARNING]
When used in a SSR environment, createSharedComposable will automatically fallback to a non-shared version.This means every call will create a fresh instance in SSR to avoid cross-request state pollution.
Usage
import { createSharedComposable, useMouse } from '@vueuse/core'
const useSharedMouse = createSharedComposable(useMouse)
// CompA.vue
const { x, y } = useSharedMouse()
// CompB.vue - will reuse the previous state and no new event listeners will be registered
const { x, y } = useSharedMouse()Type Declarations
export type SharedComposableReturn<T extends AnyFn = AnyFn> = T
/**
* Make a composable function usable with multiple Vue instances.
*
* @see https://vueuse.org/createSharedComposable
*
* @__NO_SIDE_EFFECTS__
*/
export declare function createSharedComposable<Fn extends AnyFn>(
composable: Fn,
): SharedComposableReturn<Fn>createTemplatePromise
Template as Promise. Useful for constructing custom Dialogs, Modals, Toasts, etc.
Usage
<script setup lang="ts">
import { createTemplatePromise } from '@vueuse/core'
const TemplatePromise = createTemplatePromise<ReturnType>()
async function open() {
const result = await TemplatePromise.start()
// button is clicked, result is 'ok'
}
</script>
<template>
<TemplatePromise v-slot="{ promise, resolve, reject, args }">
<!-- your UI -->
<button @click="resolve('ok')">
OK
</button>
</TemplatePromise>
</template>Features
- Programmatic - call your UI as a promise
- Template - use Vue template to render, not a new DSL
- TypeScript - full type safety via generic type
- Renderless - you take full control of the UI
- Transition - use support Vue transition
This function is migrated from vue-template-promise
Usage
createTemplatePromise returns a Vue Component that you can directly use in your template with <script setup>
```ts twoslash include main import { createTemplatePromise } from '@vueuse/core'
const TemplatePromise = createTemplatePromise() const MyPromise = createTemplatePromise<boolean>() // with generic type
In template, use `v-slot` to access the promise and resolve functions.
<template> <TemplatePromise v-slot="{ promise, resolve, reject, args }"> <!-- you can have anything --> <button @click="resolve('ok')"> OK </button> </TemplatePromise> <MyPromise v-slot="{ promise, resolve, reject, args }"> <!-- another one --> </MyPromise> </template>
The slot will not be rendered initially (similar to `v-if="false"`), until you call the `start` method from the component.
// @include: main // ---cut--- const result = await TemplatePromise.start()
Once `resolve` or `reject` is called in the template, the promise will be resolved or rejected, returning the value you passed in. Once resolved, the slot will be removed automatically.
### Passing Arguments
You can pass arguments to the `start` with arguments.
import { createTemplatePromise } from '@vueuse/core'
const TemplatePromise = createTemplatePromise<boolean, [string, number]>()
// @include: passing-arguments // ---cut--- const result = await TemplatePromise.start('hello', 123) // Pr
And in the template slot, you can access the arguments via `args` property.
<template> <TemplatePromise v-slot="{ args, resolve }"> <div>{{ args[0] }}</div> <!-- hello --> <div>{{ args[1] }}</div> <!-- 123 --> <button @click="resolve(true)"> OK </button> </TemplatePromise> </template>
### Singleton Mode
Use the `singleton` option to ensure only one instance of the promise can be active at a time. If `start` is called while a promise is already active, it will return the existing promise instead of creating a new one.
import { createTemplatePromise } from '@vueuse/core'
const TemplatePromise = createTemplatePromise<boolean>({ singleton: true, })
// These will return the same promise if called in quick succession const result1 = TemplatePromise.start() const result2 = TemplatePromise.start() // returns the same promise as result1
### Transition
You can use transition to animate the slot.
<script setup lang="ts"> const TemplatePromise = createTemplatePromise<ReturnType>({ transition: { name: 'fade', appear: true, }, }) </script>
<template> <TemplatePromise v-slot="{ resolve }"> <!-- your UI --> <button @click="resolve('ok')"> OK </button> </TemplatePromise> </template>
<style scoped> .fade-enter-active, .fade-leave-active { transition: opacity 0.5s; } .fade-enter, .fade-leave-to { opacity: 0; } </style>
Learn more about [Vue Transition](https://vuejs.org/guide/built-ins/transition.html).
### Slot Props
The slot provides the following props:
| Prop | Type | Description |
| ------------- | ---------------------------------------- | --------------------------------------------------------- |
| `promise` | `Promise<Return> \| undefined` | The current promise instance |
| `resolve` | `(v: Return \| Promise<Return>) => void` | Resolve the promise with a value |
| `reject` | `(v: any) => void` | Reject the promise |
| `args` | `Args` | Arguments passed to `start()` |
| `isResolving` | `boolean` | `true` when resolving another promise passed to `resolve` |
| `key` | `number` | Unique key for list rendering |
<template> <TemplatePromise v-slot="{ promise, resolve, reject, args, isResolving }"> <div v-if="isResolving"> Loading... </div> <div v-else> <button @click="resolve('ok')"> OK </button> <button @click="reject('cancelled')"> Cancel </button> </div> </TemplatePromise> </template>
## Motivation
The common approach to call a dialog or a modal programmatically would be like this:
const dialog = useDialog() const result = await dialog.open({ title: 'Hello', content: 'World', })
This would work by sending these information to the top-level component and let it render the dialog. However, it limits the flexibility you could express in the UI. For example, you could want the title to be red, or have extra buttons, etc. You would end up with a lot of options like:
const result = await dialog.open({ title: 'Hello', titleClass: 'text-red', content: 'World', contentClass: 'text-blue text-sm', buttons: [ { text: 'OK', class: 'bg-red', onClick: () => {} }, { text: 'Cancel', class: 'bg-blue', onClick: () => {} }, ], // ... })
Even this is not flexible enough. If you want more, you might end up with manual render function.
const result = await dialog.open({ title: 'Hello', contentSlot: () => h(MyComponent, { content }), })
This is like reinventing a new DSL in the script to express the UI template.
So this function allows **expressing the UI in templates instead of scripts**, where it is supposed to be, while still being able to be manipulated programmatically.
## Type Declarations
export interface TemplatePromiseProps<Return, Args extends any[] = []> { /**
- The promise instance.
/ promise: Promise<Return> | undefined /*
- Resolve the promise.
/ resolve: (v: Return | Promise<Return>) => void /*
- Reject the promise.
/ reject: (v: any) => void /*
- Arguments passed to TemplatePromise.start()
/ args: Args /*
- Indicates if the promise is resolving.
- When passing another promise to
resolve, this will be set totrueuntil the promise is resolved.
/ isResolving: boolean /*
- Options passed to createTemplatePromise()
/ options: TemplatePromiseOptions /*
- Unique key for list rendering.
/ key: number } export interface TemplatePromiseOptions { /*
- Determines if the promise can be called only once at a time.
*
- @default false
/ singleton?: boolean /*
- Transition props for the promise.
*/ transition?: TransitionGroupProps } export type TemplatePromise< Return, Args extends any[] = [],
= DefineComponent<object> & {
new (): { $slots: { default: (_: TemplatePromiseProps<Return, Args>) => any } } } & { start: (...args: Args) => Promise<Return> } /**
- Creates a template promise component.
*
- @see https://vueuse.org/createTemplatePromise
*
- @__NO_SIDE_EFFECTS__
*/ export declare function createTemplatePromise<Return, Args extends any[] = []>( options?: TemplatePromiseOptions, ): TemplatePromise<Return, Args>
createUnrefFn
Make a plain function accepting ref and raw values as arguments. Returns the same value the unconverted function returns, with proper typing.
::: tip Make sure you're using the right tool for the job. Using reactify might be more pertinent in some cases where you want to evaluate the function on each changes of it's arguments. :::
Usage
import { createUnrefFn } from '@vueuse/core'
import { shallowRef } from 'vue'
const url = shallowRef('https://httpbin.org/post')
const data = shallowRef({ foo: 'bar' })
function post(url, data) {
return fetch(url, { data })
}
const unrefPost = createUnrefFn(post)
post(url, data) /* ❌ Will throw an error because the arguments are refs */
unrefPost(url, data) /* ✔️ Will Work because the arguments will be auto unref */Type Declarations
export type UnrefFn<T> = T extends (...args: infer A) => infer R
? (
...args: {
[K in keyof A]: MaybeRef<A[K]>
}
) => R
: never
/**
* Make a plain function accepting ref and raw values as arguments.
* Returns the same value the unconverted function returns, with proper typing.
*
* @__NO_SIDE_EFFECTS__
*/
export declare function createUnrefFn<T extends Function>(fn: T): UnrefFn<T>extendRef
Add extra attributes to Ref.
Usage
Please note the extra attribute will not be accessible in Vue's template.
import { extendRef } from '@vueuse/core'
import { shallowRef } from 'vue'
const myRef = shallowRef('content')
const extended = extendRef(myRef, { foo: 'extra data' })
extended.value === 'content'
extended.foo === 'extra data'Refs will be unwrapped and be reactive
import { extendRef } from '@vueuse/core'
// ---cut---
const myRef = shallowRef('content')
const extraRef = shallowRef('extra')
const extended = extendRef(myRef, { extra: extraRef })
extended.value === 'content'
extended.extra === 'extra'
extended.extra = 'new data' // will trigger update
extraRef.value === 'new data'Type Declarations
export type ExtendRefReturn<T = any> = Ref<T>
export interface ExtendRefOptions<Unwrap extends boolean = boolean> {
/**
* Is the extends properties enumerable
*
* @default false
*/
enumerable?: boolean
/**
* Unwrap for Ref properties
*
* @default true
*/
unwrap?: Unwrap
}
/**
* Overload 1: Unwrap set to false
*/
export declare function extendRef<
R extends Ref<any>,
Extend extends object,
Options extends ExtendRefOptions<false>,
>(ref: R, extend: Extend, options?: Options): ShallowUnwrapRef<Extend> & R
/**
* Overload 2: Unwrap unset or set to true
*/
export declare function extendRef<
R extends Ref<any>,
Extend extends object,
Options extends ExtendRefOptions,
>(ref: R, extend: Extend, options?: Options): Extend & Rfrom / fromEvent
Wrappers around RxJS's `from()` and `fromEvent()` to allow them to accept refs.
Usage
<!-- TODO: import rxjs error if enable twoslash -->
```ts no-twoslash import { from, fromEvent, toObserver, useSubscription } from '@vueuse/rxjs' import { interval } from 'rxjs' import { map, mapTo, takeUntil, withLatestFrom } from 'rxjs/operators' import { shallowRef, useTemplateRef } from 'vue'
const count = shallowRef(0) const button = useTemplateRef('buttonRef')
useSubscription( interval(1000) .pipe( mapTo(1), takeUntil(fromEvent(button, 'click')), withLatestFrom(from(count, { immediate: true, deep: false, })), map(([curr, total]) => curr + total), ) .subscribe(toObserver(count)), // same as ).subscribe(val => (count.value = val)) )
## from
The `from` function can accept either a standard RxJS `ObservableInput` or a Vue `ref`. When passed a ref, it creates an Observable that emits whenever the ref's value changes.
### Watch Options
When using `from` with a ref, you can pass Vue's `WatchOptions`:
| Option | Type | Description |
| ----------- | --------------------------- | ---------------------------------- |
| `immediate` | `boolean` | Emit the current value immediately |
| `deep` | `boolean` | Deeply watch nested objects |
| `flush` | `'pre' \| 'post' \| 'sync'` | Timing of the callback flush |
## fromEvent
The `fromEvent` function extends RxJS's `fromEvent` to accept a ref to an element. When the ref's value changes (e.g., after the component mounts), it automatically subscribes to the new element.
import { fromEvent, useSubscription } from '@vueuse/rxjs' import { useTemplateRef } from 'vue'
const button = useTemplateRef('buttonRef')
// Will automatically subscribe when the button element becomes available useSubscription( fromEvent(button, 'click').subscribe(() => { console.log('clicked!') }) )
## Type Declarations
export declare function from<T>( value: ObservableInput<T> | Ref<T>, watchOptions?: WatchOptions, ): Observable<T> export declare function fromEvent<T extends HTMLElement | null>( value: MaybeRef<T>, event: string, ): Observable<Event>
get
Shorthand for accessing ref.value
Usage
import { get } from '@vueuse/core'
const a = ref(42)
console.log(get(a)) // 42Type Declarations
/**
* Shorthand for accessing `ref.value`
*/
export declare function get<T>(ref: MaybeRef<T>): T
export declare function get<T, K extends keyof T>(
ref: MaybeRef<T>,
key: K,
): T[K]injectLocal
Extended inject with ability to call provideLocal to provide the value in the same component.
Usage
<script setup>
import { injectLocal, provideLocal } from '@vueuse/core'
provideLocal('MyInjectionKey', 1)
const injectedValue = injectLocal('MyInjectionKey') // injectedValue === 1
</script>Type Declarations
/**
* On the basis of `inject`, it is allowed to directly call inject to obtain the value after call provide in the same component.
*
* @example
* ```ts
* injectLocal('MyInjectionKey', 1)
* const injectedValue = injectLocal('MyInjectionKey') // injectedValue === 1
* ```
*
* @__NO_SIDE_EFFECTS__
*/
export declare const injectLocal: typeof injectisDefined
Non-nullish checking type guard for Ref.
Usage
import { isDefined } from '@vueuse/core'
const example = ref(Math.random() ? 'example' : undefined) // Ref<string | undefined>
if (isDefined(example))
example // Ref<string>Type Declarations
export type IsDefinedReturn = boolean
export declare function isDefined<T>(
v: ComputedRef<T>,
): v is ComputedRef<Exclude<T, null | undefined>>
export declare function isDefined<T>(
v: Ref<T>,
): v is Ref<Exclude<T, null | undefined>>
export declare function isDefined<T>(v: T): v is Exclude<T, null | undefined>logicAnd
AND condition for refs.
Usage
import { whenever } from '@vueuse/core'
import { logicAnd } from '@vueuse/math'
const a = ref(true)
const b = ref(false)
whenever(logicAnd(a, b), () => {
console.log('both a and b are now truthy!')
})Type Declarations
/**
* `AND` conditions for refs.
*
* @see https://vueuse.org/logicAnd
*
* @__NO_SIDE_EFFECTS__
*/
export declare function logicAnd(
...args: MaybeRefOrGetter<any>[]
): ComputedRef<boolean>
/** @deprecated use `logicAnd` instead */
export declare const and: typeof logicAndlogicNot
NOT condition for ref.
Usage
import { whenever } from '@vueuse/core'
import { logicNot } from '@vueuse/math'
const a = ref(true)
whenever(logicNot(a), () => {
console.log('a is now falsy!')
})Type Declarations
/**
* `NOT` conditions for refs.
*
* @see https://vueuse.org/logicNot
*
* @__NO_SIDE_EFFECTS__
*/
export declare function logicNot(v: MaybeRefOrGetter<any>): ComputedRef<boolean>
/** @deprecated use `logicNot` instead */
export declare const not: typeof logicNotlogicOr
OR conditions for refs.
Usage
import { whenever } from '@vueuse/core'
import { logicOr } from '@vueuse/math'
const a = ref(true)
const b = ref(false)
whenever(logicOr(a, b), () => {
console.log('either a or b is truthy!')
})Type Declarations
/**
* `OR` conditions for refs.
*
* @see https://vueuse.org/logicOr
*
* @__NO_SIDE_EFFECTS__
*/
export declare function logicOr(
...args: MaybeRefOrGetter<any>[]
): ComputedRef<boolean>
/** @deprecated use `logicOr` instead */
export declare const or: typeof logicOrmakeDestructurable
Make isomorphic destructurable for object and array at the same time. See this blog for more details.
Usage
TypeScript Example:
```ts twoslash include main import { makeDestructurable } from '@vueuse/core'
const foo = { name: 'foo' } const bar = 1024
const obj = makeDestructurable( { foo, bar } as const, [foo, bar] as const, )
Usage:
// @include: main // ---cut--- let { foo, bar } = obj let [foo, bar] = obj
## Type Declarations
export declare function makeDestructurable< T extends Record<string, unknown>, A extends readonly any[], >(obj: T, arr: A): T & A
onClickOutside
Listen for clicks outside of an element. Useful for modals or dropdowns.
Usage
<script setup lang="ts">
import { onClickOutside } from '@vueuse/core'
import { useTemplateRef } from 'vue'
const target = useTemplateRef('target')
onClickOutside(target, event => console.log(event))
</script>
<template>
<div ref="target">
Hello world
</div>
<div>Outside element</div>
</template>Return Value
By default, onClickOutside returns a stop function to remove the event listeners.
const stop = onClickOutside(target, handler)
// Later, stop listening
stop()Controls
If you need more control over triggering the handler, you can use the controls option. This returns an object with stop, cancel, and trigger functions.
const { stop, cancel, trigger } = onClickOutside(
modalRef,
(event) => {
modal.value = false
},
{ controls: true },
)
// cancel prevents the next click from triggering the handler
cancel()
// trigger manually fires the handler
trigger(event)
// stop removes all event listeners
stop()Ignore Elements
Use the ignore option to prevent certain elements from triggering the handler. Provide elements as an array of Refs or CSS selectors.
const ignoreElRef = useTemplateRef('ignoreEl')
onClickOutside(
target,
event => console.log(event),
{ ignore: [ignoreElRef, '.ignore-class', '#ignore-id'] },
)Capture Phase
By default, the event listener uses the capture phase (capture: true). Set capture: false to use the bubbling phase instead.
onClickOutside(target, handler, { capture: false })Detect Iframe Clicks
Clicks inside an iframe are not detected by default. Enable detectIframe to also trigger the handler when focus moves to an iframe.
onClickOutside(target, handler, { detectIframe: true })Component Usage
<template>
<OnClickOutside :options="{ ignore: [/* ... */] }" @trigger="count++">
<div>
Click Outside of Me
</div>
</OnClickOutside>
</template>Directive Usage
<script setup lang="ts">
import { vOnClickOutside } from '@vueuse/components'
import { shallowRef } from 'vue'
const modal = shallowRef(false)
function closeModal() {
modal.value = false
}
</script>
<template>
<button @click="modal = true">
Open Modal
</button>
<div v-if="modal" v-on-click-outside="closeModal">
Hello World
</div>
</template>You can also set the handler as an array to set the configuration items of the instruction.
<script setup lang="ts">
import { vOnClickOutside } from '@vueuse/components'
import { shallowRef, useTemplateRef } from 'vue'
const modal = shallowRef(false)
const ignoreElRef = useTemplateRef('ignoreEl')
const onClickOutsideHandler = [
(ev) => {
console.log(ev)
modal.value = false
},
{ ignore: [ignoreElRef] },
]
</script>
<template>
<button @click="modal = true">
Open Modal
</button>
<div ref="ignoreElRef">
click outside ignore element
</div>
<div v-if="modal" v-on-click-outside="onClickOutsideHandler">
Hello World
</div>
</template>Type Declarations
export interface OnClickOutsideOptions<
Controls extends boolean = false,
> extends ConfigurableWindow {
/**
* List of elements that should not trigger the event,
* provided as Refs or CSS Selectors.
*/
ignore?: MaybeRefOrGetter<(MaybeElementRef | string)[]>
/**
* Use capturing phase for internal event listener.
* @default true
*/
capture?: boolean
/**
* Run handler function if focus moves to an iframe.
* @default false
*/
detectIframe?: boolean
/**
* Use controls to cancel/trigger listener.
* @default false
*/
controls?: Controls
}
export type OnClickOutsideHandler<
T extends OnClickOutsideOptions<boolean> = OnClickOutsideOptions,
> = (
event:
| (T["detectIframe"] extends true ? FocusEvent : never)
| (T["controls"] extends true ? Event : never)
| PointerEvent,
) => void
export type OnClickOutsideReturn<Controls extends boolean = false> =
Controls extends false
? Fn
: {
stop: Fn
cancel: Fn
trigger: (event: Event) => void
}
/**
* Listen for clicks outside of an element.
*
* @see https://vueuse.org/onClickOutside
* @param target
* @param handler
* @param options
*/
export declare function onClickOutside<T extends OnClickOutsideOptions>(
target: MaybeComputedElementRef,
handler: OnClickOutsideHandler<T>,
options?: T,
): Fn
export declare function onClickOutside<T extends OnClickOutsideOptions<true>>(
target: MaybeComputedElementRef,
handler: OnClickOutsideHandler<T>,
options: T,
): {
stop: Fn
cancel: Fn
trigger: (event: Event) => void
}onElementRemoval
Fires when the element or any element containing it is removed from the DOM.
Usage
```vue {13} <script setup lang="ts"> import { onElementRemoval } from '@vueuse/core' import { shallowRef, useTemplateRef } from 'vue'
const btnRef = useTemplateRef('btn') const btnState = shallowRef(true) const removedCount = shallowRef(0)
function btnOnClick() { btnState.value = !btnState.value }
onElementRemoval(btnRef, () => ++removedCount.value) </script>
<template> <button v-if="btnState" @click="btnOnClick" > recreate me </button> <button v-else ref="btnRef" @click="btnOnClick" > remove me </button> <b>removed times: {{ removedCount }}</b> </template>
### Callback with Mutation Records
The callback receives an array of `MutationRecord` objects that triggered the removal.
import { onElementRemoval } from '@vueuse/core'
onElementRemoval(targetRef, (mutationRecords) => { console.log('Element removed', mutationRecords) })
### Return Value
Returns a stop function to stop observing.
const stop = onElementRemoval(targetRef, callback)
// Later, stop observing stop()
## Type Declarations
export interface OnElementRemovalOptions extends ConfigurableWindow, ConfigurableDocumentOrShadowRoot, WatchOptionsBase {} /**
- Fires when the element or any element containing it is removed.
*
- @param target
- @param callback
- @param options
*/ export declare function onElementRemoval( target: MaybeElementRef, callback: (mutationRecords: MutationRecord[]) => void, options?: OnElementRemovalOptions, ): Fn
onKeyStroke
Listen for keyboard keystrokes. By default, listens on keydown events on window.
Usage
import { onKeyStroke } from '@vueuse/core'
onKeyStroke('ArrowDown', (e) => {
e.preventDefault()
})See this table for all key codes.
Return Value
Returns a stop function to remove the event listener.
const stop = onKeyStroke('Escape', handler)
// Later, stop listening
stop()Listen To Multiple Keys
import { onKeyStroke } from '@vueuse/core'
onKeyStroke(['s', 'S', 'ArrowDown'], (e) => {
e.preventDefault()
})
// listen to all keys by passing `true` or skipping the key parameter
onKeyStroke(true, (e) => {
e.preventDefault()
})
onKeyStroke((e) => {
e.preventDefault()
})Custom Key Predicate
You can pass a custom function to determine which keys should trigger the handler.
import { onKeyStroke } from '@vueuse/core'
onKeyStroke(
e => e.key === 'A' && e.shiftKey,
(e) => {
console.log('Shift+A pressed')
},
)Custom Event Target
import { onKeyStroke } from '@vueuse/core'
onKeyStroke('A', (e) => {
console.log('Key A pressed on document')
}, { target: document })Ignore Repeated Events
The callback will trigger only once when pressing A and holding down. The dedupe option can also be a reactive ref.
import { onKeyStroke } from '@vueuse/core'
onKeyStroke('A', (e) => {
console.log('Key A pressed')
}, { dedupe: true })Reference: KeyboardEvent.repeat
Passive Mode
Set passive: true to use a passive event listener.
import { onKeyStroke } from '@vueuse/core'
onKeyStroke('A', handler, { passive: true })Directive Usage
<script setup lang="ts">
import { vOnKeyStroke } from '@vueuse/components'
function onUpdate(e: KeyboardEvent) {
// impl...
}
</script>
<template>
<input v-on-key-stroke:c,v="onUpdate" type="text">
<!-- with options -->
<input v-on-key-stroke:c,v="[onUpdate, { eventName: 'keyup' }]" type="text">
</template>Custom Keyboard Event
import { onKeyStroke } from '@vueuse/core'
// ---cut---
onKeyStroke('Shift', (e) => {
console.log('Shift key up')
}, { eventName: 'keyup' })Or
import { onKeyUp } from '@vueuse/core'
// ---cut---
onKeyUp('Shift', () => console.log('Shift key up'))Shorthands
onKeyDown- alias foronKeyStroke(key, handler, {eventName: 'keydown'})onKeyPressed- alias foronKeyStroke(key, handler, {eventName: 'keypress'})onKeyUp- alias foronKeyStroke(key, handler, {eventName: 'keyup'})
Type Declarations
export type KeyPredicate = (event: KeyboardEvent) => boolean
export type KeyFilter = true | string | string[] | KeyPredicate
export type KeyStrokeEventName = "keydown" | "keypress" | "keyup"
export interface OnKeyStrokeOptions {
eventName?: KeyStrokeEventName
target?: MaybeRefOrGetter<EventTarget | null | undefined>
passive?: boolean
/**
* Set to `true` to ignore repeated events when the key is being held down.
*
* @default false
*/
dedupe?: MaybeRefOrGetter<boolean>
}
/**
* Listen for keyboard keystrokes.
*
* @see https://vueuse.org/onKeyStroke
*/
export declare function onKeyStroke(
key: KeyFilter,
handler: (event: KeyboardEvent) => void,
options?: OnKeyStrokeOptions,
): () => void
export declare function onKeyStroke(
handler: (event: KeyboardEvent) => void,
options?: OnKeyStrokeOptions,
): () => void
/**
* Listen to the keydown event of the given key.
*
* @see https://vueuse.org/onKeyStroke
* @param key
* @param handler
* @param options
*/
export declare function onKeyDown(
key: KeyFilter,
handler: (event: KeyboardEvent) => void,
options?: Omit<OnKeyStrokeOptions, "eventName">,
): () => void
/**
* Listen to the keypress event of the given key.
*
* @see https://vueuse.org/onKeyStroke
* @param key
* @param handler
* @param options
*/
export declare function onKeyPressed(
key: KeyFilter,
handler: (event: KeyboardEvent) => void,
options?: Omit<OnKeyStrokeOptions, "eventName">,
): () => void
/**
* Listen to the keyup event of the given key.
*
* @see https://vueuse.org/onKeyStroke
* @param key
* @param handler
* @param options
*/
export declare function onKeyUp(
key: KeyFilter,
handler: (event: KeyboardEvent) => void,
options?: Omit<OnKeyStrokeOptions, "eventName">,
): () => voidonLongPress
Listen for a long press on an element. Returns a stop function.
Usage
<script setup lang="ts">
import { onLongPress } from '@vueuse/core'
import { shallowRef, useTemplateRef } from 'vue'
const htmlRefHook = useTemplateRef('htmlRefHook')
const longPressedHook = shallowRef(false)
function onLongPressCallbackHook(e: PointerEvent) {
longPressedHook.value = true
}
function resetHook() {
longPressedHook.value = false
}
onLongPress(
htmlRefHook,
onLongPressCallbackHook,
{
modifiers: {
prevent: true
}
}
)
</script>
<template>
<p>Long Pressed: {{ longPressedHook }}</p>
<button ref="htmlRefHook" class="ml-2 button small">
Press long
</button>
<button class="ml-2 button small" @click="resetHook">
Reset
</button>
</template>Custom Delay
By default, the handler fires after 500ms. You can customize this with the delay option. It can be a number or a function that receives the PointerEvent.
import { onLongPress } from '@vueuse/core'
// Fixed delay
onLongPress(target, handler, { delay: 1000 })
// Dynamic delay based on event
onLongPress(target, handler, {
delay: ev => ev.pointerType === 'touch' ? 800 : 500,
})Distance Threshold
The long press will be canceled if the pointer moves more than the threshold (default: 10 pixels). Set to false to disable movement detection.
import { onLongPress } from '@vueuse/core'
// Custom threshold
onLongPress(target, handler, { distanceThreshold: 20 })
// Disable movement detection
onLongPress(target, handler, { distanceThreshold: false })On Mouse Up Callback
You can provide an onMouseUp callback to be notified when the pointer is released.
import { onLongPress } from '@vueuse/core'
onLongPress(target, handler, {
onMouseUp(duration, distance, isLongPress, pointerEvent) {
console.log(`Held for ${duration}ms, moved ${distance}px, long press: ${isLongPress}, x: ${pointerEvent.clientX}`)
},
})Modifiers
The following modifiers are available:
| Modifier | Description |
|---|---|
stop | Calls event.stopPropagation() |
once | Removes event listener after first trigger |
prevent | Calls event.preventDefault() |
capture | Uses capture mode for event listener |
self | Only trigger if target is the element itself |
onLongPress(target, handler, {
modifiers: {
prevent: true,
stop: true,
},
})Component Usage
<script setup lang="ts">
import { OnLongPress } from '@vueuse/components'
import { shallowRef } from 'vue'
const longPressedComponent = shallowRef(false)
function onLongPressCallbackComponent(e: PointerEvent) {
longPressedComponent.value = true
}
function resetComponent() {
longPressedComponent.value = false
}
</script>
<template>
<p>Long Pressed: {{ longPressedComponent }}</p>
<OnLongPress
as="button"
class="ml-2 button small"
@trigger="onLongPressCallbackComponent"
>
Press long
</OnLongPress>
<button class="ml-2 button small" @click="resetComponent">
Reset
</button>
</template>Directive Usage
<script setup lang="ts">
import { vOnLongPress } from '@vueuse/components'
import { shallowRef } from 'vue'
const longPressedDirective = shallowRef(false)
function onLongPressCallbackDirective(e: PointerEvent) {
longPressedDirective.value = true
}
function resetDirective() {
longPressedDirective.value = false
}
</script>
<template>
<p>Long Pressed: {{ longPressedDirective }}</p>
<button
v-on-long-press.prevent="onLongPressCallbackDirective"
class="ml-2 button small"
>
Press long
</button>
<button
v-on-long-press="[onLongPressCallbackDirective, { delay: 1000, modifiers: { stop: true } }]"
class="ml-2 button small"
>
Press long (with options)
</button>
<button class="ml-2 button small" @click="resetDirective">
Reset
</button>
</template>Type Declarations
export interface OnLongPressOptions {
/**
* Time in ms till `longpress` gets called
*
* @default 500
*/
delay?: number | ((ev: PointerEvent) => number)
modifiers?: OnLongPressModifiers
/**
* Allowance of moving distance in pixels,
* The action will get canceled When moving too far from the pointerdown position.
* @default 10
*/
distanceThreshold?: number | false
/**
* Function called when the ref element is released.
* @param duration how long the element was pressed in ms
* @param distance distance from the pointerdown position
* @param isLongPress whether the action was a long press or not
* @param pointerEvent the native {@link PointerEvent} triggered by the browser
*/
onMouseUp?: (
duration: number,
distance: number,
isLongPress: boolean,
pointerEvent: PointerEvent,
) => void
}
export interface OnLongPressModifiers {
stop?: boolean
once?: boolean
prevent?: boolean
capture?: boolean
self?: boolean
}
export type OnLongPressReturn = () => void
/** @deprecated use {@link OnLongPressReturn} instead */
export type UseOnLongPressReturn = OnLongPressReturn
export declare function onLongPress(
target: MaybeElementRef,
handler: (evt: PointerEvent) => void,
options?: OnLongPressOptions,
): OnLongPressReturnonStartTyping
Fires when users start typing on non-editable elements. Useful for auto-focusing an input field when the user starts typing anywhere on the page.
Usage
<script setup lang="ts">
import { onStartTyping } from '@vueuse/core'
import { useTemplateRef } from 'vue'
const input = useTemplateRef('input')
onStartTyping(() => {
if (!input.value.active)
input.value.focus()
})
</script>
<template>
<input ref="input" type="text" placeholder="Start typing to focus">
</template>How It Works
The callback only fires when:
- No editable element (
<input>,<textarea>, orcontenteditable) is focused - The pressed key is alphanumeric (A-Z, 0-9)
- No modifier keys (Ctrl, Alt, Meta) are held
This allows users to start typing anywhere on the page without accidentally triggering the callback when using keyboard shortcuts or interacting with form fields.
Type Declarations
/**
* Fires when users start typing on non-editable elements.
*
* @see https://vueuse.org/onStartTyping
* @param callback
* @param options
*/
export declare function onStartTyping(
callback: (event: KeyboardEvent) => void,
options?: ConfigurableDocument,
): voidprovideLocal
Extended provide with ability to call injectLocal to obtain the value in the same component.
Usage
<script setup>
import { injectLocal, provideLocal } from '@vueuse/core'
provideLocal('MyInjectionKey', 1)
const injectedValue = injectLocal('MyInjectionKey') // injectedValue === 1
</script>Type Declarations
export type ProvideLocalReturn = void
/**
* On the basis of `provide`, it is allowed to directly call inject to obtain the value after call provide in the same component.
*
* @example
* ```ts
* provideLocal('MyInjectionKey', 1)
* const injectedValue = injectLocal('MyInjectionKey') // injectedValue === 1
* ```
*/
export declare function provideLocal<T, K = LocalProvidedKey<T>>(
key: K,
value: K extends InjectionKey<infer V> ? V : T,
): ProvideLocalReturnreactify
Converts plain functions into reactive functions. The converted function accepts refs as its arguments and returns a ComputedRef, with proper typing.
::: tip Interested to see some application or looking for some pre-reactified functions?
Check out ⚗️ Vue Chemistry! :::
Usage
Basic example
import { reactify } from '@vueuse/core'
import { shallowRef } from 'vue'
// a plain function
function add(a: number, b: number): number {
return a + b
}
// now it accept refs and returns a computed ref
// (a: number | Ref<number>, b: number | Ref<number>) => ComputedRef<number>
const reactiveAdd = reactify(add)
const a = shallowRef(1)
const b = shallowRef(2)
const sum = reactiveAdd(a, b)
console.log(sum.value) // 3
a.value = 5
console.log(sum.value) // 7An example of implementing a reactive Pythagorean theorem.
<!-- eslint-skip -->
import { reactify } from '@vueuse/core'
import { shallowRef } from 'vue'
const pow = reactify(Math.pow)
const sqrt = reactify(Math.sqrt)
const add = reactify((a: number, b: number) => a + b)
const a = shallowRef(3)
const b = shallowRef(4)
const c = sqrt(add(pow(a, 2), pow(b, 2)))
console.log(c.value) // 5
// 5:12:13
a.value = 5
b.value = 12
console.log(c.value) // 13You can also do it this way:
import { reactify } from '@vueuse/core'
import { shallowRef } from 'vue'
function pythagorean(a: number, b: number) {
return Math.sqrt(a ** 2 + b ** 2)
}
const a = shallowRef(3)
const b = shallowRef(4)
const c = reactify(pythagorean)(a, b)
console.log(c.value) // 5Another example of making reactive stringify
import { reactify } from '@vueuse/core'
import { shallowRef } from 'vue'
const stringify = reactify(JSON.stringify)
const obj = shallowRef(42)
const dumped = stringify(obj)
console.log(dumped.value) // '42'
obj.value = { foo: 'bar' }
console.log(dumped.value) // '{"foo":"bar"}'Type Declarations
export type Reactified<T, Computed extends boolean> = T extends (
...args: infer A
) => infer R
? (
...args: {
[K in keyof A]: Computed extends true
? MaybeRefOrGetter<A[K]>
: MaybeRef<A[K]>
}
) => ComputedRef<R>
: never
export type ReactifyReturn<
T extends AnyFn = AnyFn,
K extends boolean = true,
> = Reactified<T, K>
export interface ReactifyOptions<T extends boolean> {
/**
* Accept passing a function as a reactive getter
*
* @default true
*/
computedGetter?: T
}
/**
* Converts plain function into a reactive function.
* The converted function accepts refs as it's arguments
* and returns a ComputedRef, with proper typing.
*
* @param fn - Source function
* @param options - Options
*
* @__NO_SIDE_EFFECTS__
*/
export declare function reactify<T extends AnyFn, K extends boolean = true>(
fn: T,
options?: ReactifyOptions<K>,
): ReactifyReturn<T, K>
/** @deprecated use `reactify` instead */
export declare const createReactiveFn: typeof reactifyreactifyObject
Apply reactify to an object
Usage
import { reactifyObject } from '@vueuse/core'
const reactifiedConsole = reactifyObject(console)
const a = ref('42')
reactifiedConsole.log(a) // no longer need `.value`Type Declarations
export type ReactifyNested<
T,
Keys extends keyof T = keyof T,
S extends boolean = true,
> = {
[K in Keys]: T[K] extends AnyFn ? Reactified<T[K], S> : T[K]
}
export type ReactifyObjectReturn<
T,
Keys extends keyof T,
S extends boolean = true,
> = ReactifyNested<T, Keys, S>
export interface ReactifyObjectOptions<
T extends boolean,
> extends ReactifyOptions<T> {
/**
* Includes names from Object.getOwnPropertyNames
*
* @default true
*/
includeOwnProperties?: boolean
}
/**
* Apply `reactify` to an object
*
* @__NO_SIDE_EFFECTS__
*/
export declare function reactifyObject<T extends object, Keys extends keyof T>(
obj: T,
keys?: (keyof T)[],
): ReactifyObjectReturn<T, Keys, true>
export declare function reactifyObject<
T extends object,
S extends boolean = true,
>(
obj: T,
options?: ReactifyObjectOptions<S>,
): ReactifyObjectReturn<T, keyof T, S>reactiveComputed
Computed reactive object. Instead of returning a ref that computed does, reactiveComputed returns a reactive object.
Usage
import { reactiveComputed } from '@vueuse/core'
const state = reactiveComputed(() => {
return {
foo: 'bar',
bar: 'baz',
}
})
state.bar // 'baz'Type Declarations
export type ReactiveComputedReturn<T extends object> = UnwrapNestedRefs<T>
/**
* Computed reactive object.
*/
export declare function reactiveComputed<T extends object>(
fn: ComputedGetter<T>,
): ReactiveComputedReturn<T>reactiveOmit
Reactively omit fields from a reactive object.
Usage
Basic Usage
import { reactiveOmit } from '@vueuse/core'
const obj = reactive({
x: 0,
y: 0,
elementX: 0,
elementY: 0,
})
const picked = reactiveOmit(obj, 'x', 'elementX') // { y: number, elementY: number }Predicate Usage
import { reactiveOmit } from '@vueuse/core'
const obj = reactive({
bar: 'bar',
baz: 'should be omit',
foo: 'foo2',
qux: true,
})
const picked = reactiveOmit(obj, (value, key) => key === 'baz' || value === true)
// { bar: string, foo: string }Scenarios
Selectively passing props to child
<script setup lang="ts">
import { reactiveOmit } from '@vueuse/core'
const props = defineProps<{
value: string
color?: string
font?: string
}>()
const childProps = reactiveOmit(props, 'value')
</script>
<template>
<div>
<!-- only passes "color" and "font" props to child -->
<ChildComp v-bind="childProps" />
</div>
</template>Type Declarations
export type ReactiveOmitReturn<
T extends object,
K extends keyof T | undefined = undefined,
> = [K] extends [undefined] ? Partial<T> : Omit<T, Extract<K, keyof T>>
export type ReactiveOmitPredicate<T> = (
value: T[keyof T],
key: keyof T,
) => boolean
export declare function reactiveOmit<T extends object, K extends keyof T>(
obj: T,
...keys: (K | K[])[]
): ReactiveOmitReturn<T, K>
export declare function reactiveOmit<T extends object>(
obj: T,
predicate: ReactiveOmitPredicate<T>,
): ReactiveOmitReturn<T>reactivePick
Reactively pick fields from a reactive object.
Usage
Basic Usage
import { reactivePick } from '@vueuse/core'
const obj = reactive({
x: 0,
y: 0,
elementX: 0,
elementY: 0,
})
const picked = reactivePick(obj, 'x', 'elementX') // { x: number, elementX: number }Predicate Usage
import { reactivePick } from '@vueuse/core'
const source = reactive({
foo: 'foo',
bar: 'bar',
baz: 'baz',
qux: true,
})
const state = reactivePick(source, (value, key) => key !== 'bar' && value !== true)
// { foo: string, baz: string }
source.qux = false
// { foo: string, baz: string, qux: boolean }Scenarios
Selectively passing props to child
<script setup lang="ts">
import { reactivePick } from '@vueuse/core'
const props = defineProps<{
value: string
color?: string
font?: string
}>()
const childProps = reactivePick(props, 'color', 'font')
</script>
<template>
<div>
<!-- only passes "color" and "font" props to child -->
<ChildComp v-bind="childProps" />
</div>
</template>Selectively wrap reactive object
Instead of doing this
import { useElementBounding } from '@vueuse/core'
import { reactive } from 'vue'
const { height, width } = useElementBounding() // object of refs
const size = reactive({ height, width })Now we can just have this
import { reactivePick, useElementBounding } from '@vueuse/core'
const size = reactivePick(useElementBounding(), 'height', 'width')Type Declarations
export type ReactivePickReturn<T extends object, K extends keyof T> = {
[S in K]: UnwrapRef<T[S]>
}
export type ReactivePickPredicate<T> = (
value: T[keyof T],
key: keyof T,
) => boolean
export declare function reactivePick<T extends object, K extends keyof T>(
obj: T,
...keys: (K | K[])[]
): ReactivePickReturn<T, K>
export declare function reactivePick<T extends object>(
obj: T,
predicate: ReactivePickPredicate<T>,
): ReactivePickReturn<T, keyof T>refAutoReset
A ref which will be reset to the default value after some time.
Usage
import { refAutoReset } from '@vueuse/core'
const message = refAutoReset('default message', 1000)
function setMessage() {
// here the value will change to 'message has set' but after 1000ms, it will change to 'default message'
message.value = 'message has set'
}::: info You can reassign the entire object to trigger updates after making deep mutations to the inner value.
Learn more about shallow refs → :::
Type Declarations
export type RefAutoResetReturn<T = any> = Ref<T>
/**
* Create a ref which will be reset to the default value after some time.
*
* @see https://vueuse.org/refAutoReset
* @param defaultValue The value which will be set.
* @param afterMs A zero-or-greater delay in milliseconds.
*/
export declare function refAutoReset<T>(
defaultValue: MaybeRefOrGetter<T>,
afterMs?: MaybeRefOrGetter<number>,
): RefAutoResetReturn<T>
/** @deprecated use `refAutoReset` instead */
export declare const autoResetRef: typeof refAutoResetrefDebounced
Debounce execution of a ref value.
Usage
```ts {5} import { refDebounced } from '@vueuse/core' import { shallowRef } from 'vue'
const input = shallowRef('foo') const debounced = refDebounced(input, 1000)
input.value = 'bar' console.log(debounced.value) // 'foo'
await sleep(1100)
console.log(debounced.value) // 'bar' // ---cut-after--- function sleep(ms: number) { return new Promise(resolve => setTimeout(resolve, ms)) }
An example with object ref.
import { refDebounced } from '@vueuse/core' import { shallowRef } from 'vue'
const data = shallowRef({ name: 'foo', age: 18, }) const debounced = refDebounced(data, 1000)
function update() { data.value = { ...data.value, name: 'bar', } }
console.log(debounced.value) // { name: 'foo', age: 18 } update() await sleep(1100)
console.log(debounced.value) // { name: 'bar', age: 18 }
You can also pass an optional 3rd parameter including maxWait option. See `useDebounceFn` for details.
## Recommended Reading
- [**Debounce vs Throttle**: Definitive Visual Guide](https://kettanaito.com/blog/debounce-vs-throttle)
## Type Declarations
export type RefDebouncedReturn<T = any> = Readonly<Ref<T>> /**
- Debounce updates of a ref.
*
- @return A new debounced ref.
/ export declare function refDebounced<T>( value: Ref<T>, ms?: MaybeRefOrGetter<number>, options?: DebounceFilterOptions, ): RefDebouncedReturn<T> / @deprecated use `refDebounced` instead / export declare const debouncedRef: typeof refDebounced /* @deprecated use `refDebounced` instead / export declare const useDebounce: typeof refDebounced
refDefault
Apply default value to a ref.
Usage
import { refDefault, useStorage } from '@vueuse/core'
const raw = useStorage('key')
const state = refDefault(raw, 'default')
raw.value = 'hello'
console.log(state.value) // hello
raw.value = undefined
console.log(state.value) // defaultType Declarations
/**
* Apply default value to a ref.
*
* @__NO_SIDE_EFFECTS__
*/
export declare function refDefault<T>(
source: Ref<T | undefined | null>,
defaultValue: T,
): Ref<T>refManualReset
Create a ref with manual reset functionality.
Usage
import { refManualReset } from '@vueuse/core'
const message = refManualReset('default message')
message.value = 'message has set'
message.reset()
console.log(message.value) // 'default message'[!NOTE]
refManualReset is shallow, which may cause your UI not updated on value changes.Wrap your value with reactive can achieve deep reactivity, but this workaround may not suit all use cases.Type Declarations
/**
* Define the shape of a ref that supports manual reset functionality.
*
* This interface extends the standard `Ref` type from Vue and adds a `reset` method.
* The `reset` method allows the ref to be manually reset to its default value.
*/
export interface ManualResetRefReturn<T> extends Ref<T> {
reset: Fn
}
/**
* Create a ref with manual reset functionality.
*
* @see https://vueuse.org/refManualReset
* @param defaultValue The value which will be set.
*/
export declare function refManualReset<T>(
defaultValue: MaybeRefOrGetter<T>,
): ManualResetRefReturn<T>refThrottled
Throttle changing of a ref value.
Usage
import { refThrottled } from '@vueuse/core'
import { shallowRef } from 'vue'
const input = shallowRef('')
const throttled = refThrottled(input, 1000)An example with object ref.
import { refThrottled } from '@vueuse/core'
import { shallowRef } from 'vue'
const data = shallowRef({
count: 0,
name: 'foo',
})
const throttled = refThrottled(data, 1000)
data.value = { count: 1, name: 'foo' }
console.log(throttled.value) // { count: 1, name: 'foo' } (immediate)
data.value = { count: 2, name: 'bar' }
data.value = { count: 3, name: 'baz' }
data.value = { count: 4, name: 'qux' }
console.log(throttled.value) // { count: 1, name: 'foo' } (still first value)
// After 1000ms, next change will be applied
await sleep(1100)
data.value = { count: 5, name: 'final' }
await nextTick()
console.log(throttled.value) // { count: 5, name: 'final' } (updated)Trailing
If you don't want to watch trailing changes, set 3rd param false (it's true by default):
import { refThrottled } from '@vueuse/core'
import { shallowRef } from 'vue'
const input = shallowRef('')
const throttled = refThrottled(input, 1000, false)Leading
Allows the callback to be invoked immediately (on the leading edge of the ms timeout). If you don't want this behavior, set the 4th param false (it's true by default):
import { refThrottled } from '@vueuse/core'
import { shallowRef } from 'vue'
const input = shallowRef('')
const throttled = refThrottled(input, 1000, undefined, false)Recommended Reading
Type Declarations
export type RefThrottledReturn<T = any> = Ref<T>
/**
* Throttle execution of a function. Especially useful for rate limiting
* execution of handlers on events like resize and scroll.
*
* @param value Ref value to be watched with throttle effect
* @param delay A zero-or-greater delay in milliseconds. For event callbacks, values around 100 or 250 (or even higher) are most useful.
* @param trailing if true, update the value again after the delay time is up
* @param leading if true, update the value on the leading edge of the ms timeout
*/
export declare function refThrottled<T = any>(
value: Ref<T>,
delay?: number,
trailing?: boolean,
leading?: boolean,
): RefThrottledReturn<T>
/** @deprecated use `refThrottled` instead */
export declare const throttledRef: typeof refThrottled
/** @deprecated use `refThrottled` instead */
export declare const useThrottle: typeof refThrottledrefWithControl
Fine-grained controls over ref and its reactivity.
Usage
refWithControl uses extendRef to provide two extra functions get and set to have better control over when it should track/trigger the reactivity.
import { refWithControl } from '@vueuse/core'
const num = refWithControl(0)
const doubled = computed(() => num.value * 2)
// just like normal ref
num.value = 42
console.log(num.value) // 42
console.log(doubled.value) // 84
// set value without triggering the reactivity
num.set(30, false)
console.log(num.value) // 30
console.log(doubled.value) // 84 (doesn't update)
// get value without tracking the reactivity
watchEffect(() => {
console.log(num.peek())
}) // 30
num.value = 50 // watch effect wouldn't be triggered since it collected nothing.
console.log(doubled.value) // 100 (updated again since it's a reactive set)peek, lay, untrackedGet, silentSet
We also provide some shorthands for doing the get/set without track/triggering the reactivity system. The following lines are equivalent.
import { refWithControl } from '@vueuse/core'
// ---cut---
const foo = refWithControl('foo')import { refWithControl } from '@vueuse/core'
const foo = refWithControl('foo')
// ---cut---
// getting
foo.get(false)
foo.untrackedGet()
foo.peek() // an alias for `untrackedGet`import { refWithControl } from '@vueuse/core'
const foo = refWithControl('foo')
// ---cut---
// setting
foo.set('bar', false)
foo.silentSet('bar')
foo.lay('bar') // an alias for `silentSet`Configurations
onBeforeChange()
onBeforeChange option is offered to give control over if a new value should be accepted. For example:
import { refWithControl } from '@vueuse/core'
// ---cut---
const num = refWithControl(0, {
onBeforeChange(value, oldValue) {
// disallow changes larger then ±5 in one operation
if (Math.abs(value - oldValue) > 5)
return false // returning `false` to dismiss the change
},
})
num.value += 1
console.log(num.value) // 1
num.value += 6
console.log(num.value) // 1 (change been dismissed)onChanged()
onChanged option offers a similar functionally as Vue's watch but being synchronized with less overhead compared to watch.
import { refWithControl } from '@vueuse/core'
// ---cut---
const num = refWithControl(0, {
onChanged(value, oldValue) {
console.log(value)
},
})Type Declarations
export interface ControlledRefOptions<T> {
/**
* Callback function before the ref changing.
*
* Returning `false` to dismiss the change.
*/
onBeforeChange?: (value: T, oldValue: T) => void | boolean
/**
* Callback function after the ref changed
*
* This happens synchronously, with less overhead compare to `watch`
*/
onChanged?: (value: T, oldValue: T) => void
}
/**
* Fine-grained controls over ref and its reactivity.
*
* @__NO_SIDE_EFFECTS__
*/
export declare function refWithControl<T>(
initial: T,
options?: ControlledRefOptions<T>,
): {
get: (tracking?: boolean) => T
set: (value: T, triggering?: boolean) => void
untrackedGet: () => T
silentSet: (v: T) => void
peek: () => T
lay: (v: T) => void
} & Ref<T, T>
/** @deprecated use `refWithControl` instead */
export declare const controlledRef: typeof refWithControlset
Shorthand for ref.value = x
Usage
import { set } from '@vueuse/core'
const a = ref(0)
set(a, 1)
console.log(a.value) // 1Type Declarations
export declare function set<T>(ref: Ref<T>, value: T): void
export declare function set<O extends object, K extends keyof O>(
target: O,
key: K,
value: O[K],
): voidsyncRef
Two-way refs synchronization.
Usage
import { syncRef } from '@vueuse/core'
const a = ref('a')
const b = ref('b')
const stop = syncRef(a, b)
console.log(a.value) // a
b.value = 'foo'
console.log(a.value) // foo
a.value = 'bar'
console.log(b.value) // barOne directional
import { syncRef } from '@vueuse/core'
const a = ref('a')
const b = ref('b')
const stop = syncRef(a, b, { direction: 'rtl' })Custom Transform
import { syncRef } from '@vueuse/core'
const a = ref(10)
const b = ref(2)
const stop = syncRef(a, b, {
transform: {
ltr: left => left * 2,
rtl: right => right / 2
}
})
console.log(b.value) // 20
b.value = 30
console.log(a.value) // 15Type Declarations
type Direction = "ltr" | "rtl" | "both"
type SpecificFieldPartial<T, K extends keyof T> = Partial<Pick<T, K>> &
Omit<T, K>
/**
* A = B
*/
type Equal<A, B> = [A] extends [B] ? ([B] extends [A] ? true : false) : false
/**
* A ∩ B ≠ ∅
*/
type IntersectButNotEqual<A, B> =
Equal<A, B> extends true ? false : A & B extends never ? false : true
/**
* A ⊆ B
*/
type IncludeButNotEqual<A, B> =
Equal<A, B> extends true ? false : A extends B ? true : false
/**
* A ∩ B = ∅
*/
type NotIntersect<A, B> =
Equal<A, B> extends true ? false : A & B extends never ? true : false
interface EqualType<
D extends Direction,
L,
R,
O extends keyof Transform<L, R> = D extends "both" ? "ltr" | "rtl" : D,
> {
transform?: SpecificFieldPartial<Pick<Transform<L, R>, O>, O>
}
type StrictIncludeMap<
IncludeType extends "LR" | "RL",
D extends Exclude<Direction, "both">,
L,
R,
> = Equal<[IncludeType, D], ["LR", "ltr"]> &
Equal<[IncludeType, D], ["RL", "rtl"]> extends true
? {
transform?: SpecificFieldPartial<Pick<Transform<L, R>, D>, D>
}
: {
transform: Pick<Transform<L, R>, D>
}
type StrictIncludeType<
IncludeType extends "LR" | "RL",
D extends Direction,
L,
R,
> = D extends "both"
? {
transform: SpecificFieldPartial<
Transform<L, R>,
IncludeType extends "LR" ? "ltr" : "rtl"
>
}
: D extends Exclude<Direction, "both">
? StrictIncludeMap<IncludeType, D, L, R>
: never
type IntersectButNotEqualType<D extends Direction, L, R> = D extends "both"
? {
transform: Transform<L, R>
}
: D extends Exclude<Direction, "both">
? {
transform: Pick<Transform<L, R>, D>
}
: never
type NotIntersectType<D extends Direction, L, R> = IntersectButNotEqualType<
D,
L,
R
>
interface Transform<L, R> {
ltr: (left: L) => R
rtl: (right: R) => L
}
type TransformType<D extends Direction, L, R> =
Equal<L, R> extends true
? EqualType<D, L, R>
: IncludeButNotEqual<L, R> extends true
? StrictIncludeType<"LR", D, L, R>
: IncludeButNotEqual<R, L> extends true
? StrictIncludeType<"RL", D, L, R>
: IntersectButNotEqual<L, R> extends true
? IntersectButNotEqualType<D, L, R>
: NotIntersect<L, R> extends true
? NotIntersectType<D, L, R>
: never
export type SyncRefOptions<
L,
R,
D extends Direction,
> = ConfigurableFlushSync & {
/**
* Watch deeply
*
* @default false
*/
deep?: boolean
/**
* Sync values immediately
*
* @default true
*/
immediate?: boolean
/**
* Direction of syncing. Value will be redefined if you define syncConvertors
*
* @default 'both'
*/
direction?: D
} & TransformType<D, L, R>
/**
* Two-way refs synchronization.
* From the set theory perspective to restrict the option's type
* Check in the following order:
* 1. L = R
* 2. L ∩ R ≠ ∅
* 3. L ⊆ R
* 4. L ∩ R = ∅
*/
export declare function syncRef<L, R, D extends Direction = "both">(
left: Ref<L>,
right: Ref<R>,
...[options]: Equal<L, R> extends true
? [options?: SyncRefOptions<L, R, D>]
: [options: SyncRefOptions<L, R, D>]
): () => voidsyncRefs
Keep target refs in sync with a source ref
Usage
import { syncRefs } from '@vueuse/core'
import { shallowRef } from 'vue'
const source = shallowRef('hello')
const target = shallowRef('target')
const stop = syncRefs(source, target)
console.log(target.value) // hello
source.value = 'foo'
console.log(target.value) // fooSync with multiple targets
You can also pass an array of refs to sync.
import { syncRefs } from '@vueuse/core'
import { shallowRef } from 'vue'
const source = shallowRef('hello')
const target1 = shallowRef('target1')
const target2 = shallowRef('target2')
const stop = syncRefs(source, [target1, target2])
console.log(target1.value) // hello
console.log(target2.value) // hello
source.value = 'foo'
console.log(target1.value) // foo
console.log(target2.value) // fooWatch options
The options for syncRefs are similar to watch's WatchOptions but with different default values.
export interface SyncRefOptions {
/**
* Timing for syncing, same as watch's flush option
*
* @default 'sync'
*/
flush?: WatchOptionFlush
/**
* Watch deeply
*
* @default false
*/
deep?: boolean
/**
* Sync values immediately
*
* @default true
*/
immediate?: boolean
}When setting { flush: 'pre' }, the target reference will be updated at the end of the current "tick" before rendering starts.
import { syncRefs } from '@vueuse/core'
import { nextTick, shallowRef } from 'vue'
const source = shallowRef('hello')
const target = shallowRef('target')
syncRefs(source, target, { flush: 'pre' })
console.log(target.value) // hello
source.value = 'foo'
console.log(target.value) // hello <- still unchanged, because of flush 'pre'
await nextTick()
console.log(target.value) // foo <- changed!Type Declarations
export interface SyncRefsOptions extends ConfigurableFlushSync {
/**
* Watch deeply
*
* @default false
*/
deep?: boolean
/**
* Sync values immediately
*
* @default true
*/
immediate?: boolean
}
/**
* Keep target ref(s) in sync with the source ref
*
* @param source source ref
* @param targets
*/
export declare function syncRefs<T>(
source: WatchSource<T>,
targets: Ref<T> | Ref<T>[],
options?: SyncRefsOptions,
): WatchHandle::: info This function will be removed in future version.
Vue 3.5 introduced the useTemplateRef API which can effectively replace the functionality of templateRef, therefore we recommend using the native approach. :::
templateRef
Shorthand for binding ref to template element.
Usage
<!-- eslint-skip -->
<script lang="ts">
import { templateRef } from '@vueuse/core'
export default {
setup() {
const target = templateRef('target')
// no need to return the `target`, it will bind to the ref magically
},
}
</script>
<template>
<div ref="target" />
</template>With JSX/TSX
import { templateRef } from '@vueuse/core'
export default {
setup() {
const target = templateRef<HTMLElement | null>('target', null)
// use string ref
return () => <div ref="target"></div>
},
}<script setup>
There is no need for this when using with <script setup> since all the variables will be exposed to the template. It will be exactly the same as ref.
<script setup lang="ts">
import { ref } from 'vue'
const target = ref<HTMLElement | null>(null)
</script>
<template>
<div ref="target" />
</template>Type Declarations
/**
* @deprecated Use Vue's built-in `useTemplateRef` instead.
*
* Shorthand for binding ref to template element.
*
* @see https://vueuse.org/templateRef
* @param key
* @param initialValue
*
* @__NO_SIDE_EFFECTS__
*/
export declare function templateRef<
T extends HTMLElement | SVGElement | Component | null,
Keys extends string = string,
>(key: Keys, initialValue?: T | null): Readonly<Ref<T>>toObserver
Sugar function to convert a ref into an RxJS Observer.
Usage
<!-- TODO: import rxjs error if enable twoslash -->
```ts no-twoslash import { from, fromEvent, toObserver, useSubscription } from '@vueuse/rxjs' import { interval } from 'rxjs' import { map, mapTo, startWith, takeUntil, withLatestFrom } from 'rxjs/operators' import { shallowRef, useTemplateRef } from 'vue'
const count = shallowRef(0) const button = useTemplateRef('buttonRef')
useSubscription( interval(1000) .pipe( mapTo(1), takeUntil(fromEvent(button, 'click')), withLatestFrom(from(count).pipe(startWith(0))), map(([curr, total]) => curr + total), ) .subscribe(toObserver(count)), // same as ).subscribe(val => (count.value = val)) )
## Type Declarations
export declare function toObserver<T>(value: Ref<T>): NextObserver<T>
toReactive
Converts ref to reactive. Also made possible to create a "swapable" reactive object.
Usage
import { toReactive } from '@vueuse/core'
import { ref } from 'vue'
const refState = ref({ foo: 'bar' })
console.log(refState.value.foo) // => 'bar'
const state = toReactive(refState) // <--
console.log(state.foo) // => 'bar'
refState.value = { bar: 'foo' }
console.log(state.foo) // => undefined
console.log(state.bar) // => 'foo'Type Declarations
/**
* Converts ref to reactive.
*
* @see https://vueuse.org/toReactive
* @param objectRef A ref of object
*/
export declare function toReactive<T extends object>(
objectRef: MaybeRef<T>,
): UnwrapNestedRefs<T>toRef
Normalize value/ref/getter to ref or computed.
Usage
import { toRef } from '@vueuse/core'
const foo = ref('hi')
const a = toRef(0) // Ref<number>
const b = toRef(foo) // Ref<string>
const c = toRef(() => 'hi') // ComputedRef<string>Differences from Vue's toRef
VueUse's toRef is not the same as Vue’s toRef from the vue package.
VueUse toRef
- Accepts value, ref, or getter
- Returns:
- a ref for primitive values
- a ref for existing refs
- a computed for getter functions
- Does not accept
object + key - Getters always produce readonly computed values
Vue toRef
- Accepts only:
- a reactive object + property key, or
- an existing ref
- Produces a writable ref linked to the underlying reactive object
- Does not accept primitive values
- Does not accept getter functions
Summary
| Behavior | VueUse toRef | Vue toRef |
|---|---|---|
| Accepts primitive values | ✔️ | ❌ |
| Accepts getter | ✔️ (computed) | ❌ |
| Accepts existing ref | ✔️ | ✔️ |
| Accepts object + key | ❌ | ✔️ |
| Writable | ✔️ (except getter) | ✔️ |
| Purpose | Normalize to ref/computed | Bind to reactive object |
Type Declarations
/**
* Normalize value/ref/getter to `ref` or `computed`.
*/
export declare function toRef<T>(r: () => T): Readonly<Ref<T>>
export declare function toRef<T>(r: ComputedRef<T>): ComputedRef<T>
export declare function toRef<T>(r: MaybeRefOrGetter<T>): Ref<T>
export declare function toRef<T>(r: T): Ref<T>
export declare function toRef<T extends object, K extends keyof T>(
object: T,
key: K,
): ToRef<T[K]>
export declare function toRef<T extends object, K extends keyof T>(
object: T,
key: K,
defaultValue: T[K],
): ToRef<Exclude<T[K], undefined>>toRefs
Extended `toRefs` that also accepts refs of an object.
Usage
import { toRefs } from '@vueuse/core'
import { reactive, ref } from 'vue'
const objRef = ref({ a: 'a', b: 0 })
const arrRef = ref(['a', 0])
const { a, b } = toRefs(objRef)
const [a, b] = toRefs(arrRef)
const obj = reactive({ a: 'a', b: 0 })
const arr = reactive(['a', 0])
const { a, b } = toRefs(obj)
const [a, b] = toRefs(arr)Use-cases
Destructuring a props object
<script lang="ts">
import { toRefs, useVModel } from '@vueuse/core'
export default {
setup(props) {
const refs = toRefs(useVModel(props, 'data'))
console.log(refs.a.value) // props.data.a
refs.a.value = 'a' // emit('update:data', { ...props.data, a: 'a' })
return { ...refs }
}
}
</script>
<template>
<div>
<input v-model="a" type="text">
<input v-model="b" type="text">
</div>
</template>Type Declarations
export interface ToRefsOptions {
/**
* Replace the original ref with a copy on property update.
*
* @default true
*/
replaceRef?: MaybeRefOrGetter<boolean>
}
/**
* Extended `toRefs` that also accepts refs of an object.
*
* @see https://vueuse.org/toRefs
* @param objectRef A ref or normal object or array.
* @param options Options
*/
export declare function toRefs<T extends object>(
objectRef: MaybeRef<T>,
options?: ToRefsOptions,
): ToRefs<T>tryOnBeforeMount
Safe onBeforeMount. Call onBeforeMount() if it's inside a component lifecycle, if not, just call the function
Usage
import { tryOnBeforeMount } from '@vueuse/core'
tryOnBeforeMount(() => {
})Type Declarations
/**
* Call onBeforeMount() if it's inside a component lifecycle, if not, just call the function
*
* @param fn
* @param sync if set to false, it will run in the nextTick() of Vue
* @param target
*/
export declare function tryOnBeforeMount(
fn: Fn,
sync?: boolean,
target?: ComponentInternalInstance | null,
): voidtryOnBeforeUnmount
Safe onBeforeUnmount. Call onBeforeUnmount() if it's inside a component lifecycle, if not, do nothing
Usage
import { tryOnBeforeUnmount } from '@vueuse/core'
tryOnBeforeUnmount(() => {
})Type Declarations
/**
* Call onBeforeUnmount() if it's inside a component lifecycle, if not, do nothing
*
* @param fn
* @param target
*/
export declare function tryOnBeforeUnmount(
fn: Fn,
target?: ComponentInternalInstance | null,
): voidtryOnMounted
Safe onMounted. Call onMounted() if it's inside a component lifecycle, if not, just call the function
Usage
import { tryOnMounted } from '@vueuse/core'
tryOnMounted(() => {
})Type Declarations
/**
* Call onMounted() if it's inside a component lifecycle, if not, just call the function
*
* @param fn
* @param sync if set to false, it will run in the nextTick() of Vue
* @param target
*/
export declare function tryOnMounted(
fn: Fn,
sync?: boolean,
target?: ComponentInternalInstance | null,
): voidtryOnScopeDispose
Safe onScopeDispose. Call onScopeDispose() if it's inside an effect scope lifecycle, if not, do nothing
Usage
import { tryOnScopeDispose } from '@vueuse/core'
tryOnScopeDispose(() => {
})Type Declarations
/**
* Call onScopeDispose() if it's inside an effect scope lifecycle, if not, do nothing
*
* @param fn
*/
export declare function tryOnScopeDispose(
fn: Fn,
failSilently?: boolean,
): booleantryOnUnmounted
Safe onUnmounted. Call onUnmounted() if it's inside a component lifecycle, if not, do nothing
Usage
import { tryOnUnmounted } from '@vueuse/core'
tryOnUnmounted(() => {
})Type Declarations
/**
* Call onUnmounted() if it's inside a component lifecycle, if not, do nothing
*
* @param fn
* @param target
*/
export declare function tryOnUnmounted(
fn: Fn,
target?: ComponentInternalInstance | null,
): voidunrefElement
Retrieves the underlying DOM element from a Vue ref or component instance
Usage
<script setup lang="ts">
import { unrefElement } from '@vueuse/core'
import { onMounted, useTemplateRef } from 'vue'
const div = useTemplateRef('div') // will be bound to the <div> element
const hello = useTemplateRef('hello') // will be bound to the HelloWorld Component
onMounted(() => {
console.log(unrefElement(div)) // the <div> element
console.log(unrefElement(hello)) // the root element of the HelloWorld Component
})
</script>
<template>
<div ref="div" />
<HelloWorld ref="hello" />
</template>Type Declarations
export type VueInstance = ComponentPublicInstance
export type MaybeElementRef<T extends MaybeElement = MaybeElement> = MaybeRef<T>
export type MaybeComputedElementRef<T extends MaybeElement = MaybeElement> =
MaybeRefOrGetter<T>
export type MaybeElement =
| HTMLElement
| SVGElement
| VueInstance
| undefined
| null
export type UnRefElementReturn<T extends MaybeElement = MaybeElement> =
T extends VueInstance ? Exclude<MaybeElement, VueInstance> : T | undefined
/**
* Get the dom element of a ref of element or Vue component instance
*
* @param elRef
*/
export declare function unrefElement<T extends MaybeElement>(
elRef: MaybeComputedElementRef<T>,
): UnRefElementReturn<T>until
Promised one-time watch for changes
Usage
Wait for some async data to be ready
import { until, useAsyncState } from '@vueuse/core'
const { state, isReady } = useAsyncState(
fetch('https://jsonplaceholder.typicode.com/todos/1').then(t => t.json()),
{},
)
;(async () => {
await until(isReady).toBe(true)
console.log(state) // state is now ready!
})()Wait for custom conditions
You can use invoke to call the async function.import { invoke, until, useCounter } from '@vueuse/core'
const { count } = useCounter()
invoke(async () => {
await until(count).toMatch(v => v > 7)
alert('Counter is now larger than 7!')
})Timeout
import { until } from '@vueuse/core'
// ---cut---
// will be resolve until ref.value === true or 1000ms passed
await until(ref).toBe(true, { timeout: 1000 })
// will throw if timeout
try {
await until(ref).toBe(true, { timeout: 1000, throwOnTimeout: true })
// ref.value === true
}
catch (e) {
// timeout
}More Examples
import { until } from '@vueuse/core'
// ---cut---
await until(ref).toBe(true)
await until(ref).toMatch(v => v > 10 && v < 100)
await until(ref).changed()
await until(ref).changedTimes(10)
await until(ref).toBeTruthy()
await until(ref).toBeNull()
await until(ref).not.toBeNull()
await until(ref).not.toBeTruthy()Type Declarations
export interface UntilToMatchOptions extends ConfigurableFlushSync {
/**
* Milliseconds timeout for promise to resolve/reject if the when condition does not meet.
* 0 for never timed out
*
* @default 0
*/
timeout?: number
/**
* Reject the promise when timeout
*
* @default false
*/
throwOnTimeout?: boolean
/**
* `deep` option for internal watch
*
* @default 'false'
*/
deep?: WatchOptions["deep"]
}
export interface UntilBaseInstance<T, Not extends boolean = false> {
toMatch: (<U extends T = T>(
condition: (v: T) => v is U,
options?: UntilToMatchOptions,
) => Not extends true ? Promise<Exclude<T, U>> : Promise<U>) &
((
condition: (v: T) => boolean,
options?: UntilToMatchOptions,
) => Promise<T>)
changed: (options?: UntilToMatchOptions) => Promise<T>
changedTimes: (n?: number, options?: UntilToMatchOptions) => Promise<T>
}
type Falsy = false | void | null | undefined | 0 | 0n | ""
export interface UntilValueInstance<
T,
Not extends boolean = false,
> extends UntilBaseInstance<T, Not> {
readonly not: UntilValueInstance<T, Not extends true ? false : true>
toBe: <P = T>(
value: MaybeRefOrGetter<P>,
options?: UntilToMatchOptions,
) => Not extends true ? Promise<T> : Promise<P>
toBeTruthy: (
options?: UntilToMatchOptions,
) => Not extends true ? Promise<T & Falsy> : Promise<Exclude<T, Falsy>>
toBeNull: (
options?: UntilToMatchOptions,
) => Not extends true ? Promise<Exclude<T, null>> : Promise<null>
toBeUndefined: (
options?: UntilToMatchOptions,
) => Not extends true ? Promise<Exclude<T, undefined>> : Promise<undefined>
toBeNaN: (options?: UntilToMatchOptions) => Promise<T>
}
export interface UntilArrayInstance<T> extends UntilBaseInstance<T> {
readonly not: UntilArrayInstance<T>
toContains: (
value: MaybeRefOrGetter<ElementOf<ShallowUnwrapRef<T>>>,
options?: UntilToMatchOptions,
) => Promise<T>
}
/**
* Promised one-time watch for changes
*
* @see https://vueuse.org/until
* @example
* ```
* const { count } = useCounter()
*
* await until(count).toMatch(v => v > 7)
*
* alert('Counter is now larger than 7!')
* ```
*/
export declare function until<T extends unknown[]>(
r: WatchSource<T> | MaybeRefOrGetter<T>,
): UntilArrayInstance<T>
export declare function until<T>(
r: WatchSource<T> | MaybeRefOrGetter<T>,
): UntilValueInstance<T>useAbs
Reactive Math.abs.
Usage
import { useAbs } from '@vueuse/math'
const value = ref(-23)
const absValue = useAbs(value) // Ref<23>Type Declarations
/**
* Reactive `Math.abs`.
*
* @see https://vueuse.org/useAbs
*
* @__NO_SIDE_EFFECTS__
*/
export declare function useAbs(
value: MaybeRefOrGetter<number>,
): ComputedRef<number>useActiveElement
Reactive document.activeElement. Returns a shallow ref that updates when focus changes.
Usage
<script setup lang="ts">
import { useActiveElement } from '@vueuse/core'
import { watch } from 'vue'
const activeElement = useActiveElement()
watch(activeElement, (el) => {
console.log('focus changed to', el)
})
</script>Shadow DOM Support
By default, useActiveElement will traverse into shadow DOM to find the deeply active element. Set deep: false to disable this behavior.
import { useActiveElement } from '@vueuse/core'
// Only get the shadow host, not the element inside shadow DOM
const activeElement = useActiveElement({ deep: false })Track Element Removal
Set triggerOnRemoval: true to update the active element when the currently active element is removed from the DOM. This uses a MutationObserver under the hood.
import { useActiveElement } from '@vueuse/core'
const activeElement = useActiveElement({ triggerOnRemoval: true })Component Usage
<template>
<UseActiveElement v-slot="{ element }">
Active element is {{ element?.dataset.id }}
</UseActiveElement>
</template>Type Declarations
export interface UseActiveElementOptions
extends ConfigurableWindow, ConfigurableDocumentOrShadowRoot {
/**
* Search active element deeply inside shadow dom
*
* @default true
*/
deep?: boolean
/**
* Track active element when it's removed from the DOM
* Using a MutationObserver under the hood
* @default false
*/
triggerOnRemoval?: boolean
}
export type UseActiveElementReturn<T extends HTMLElement = HTMLElement> =
ShallowRef<T | null | undefined>
/**
* Reactive `document.activeElement`
*
* @see https://vueuse.org/useActiveElement
* @param options
*
* @__NO_SIDE_EFFECTS__
*/
export declare function useActiveElement<T extends HTMLElement>(
options?: UseActiveElementOptions,
): UseActiveElementReturn<T>useAnimate
Reactive Web Animations API.
Usage
Basic Usage
The useAnimate function returns the animation instance and control functions.
<script setup lang="ts">
import { useAnimate } from '@vueuse/core'
import { useTemplateRef } from 'vue'
const el = useTemplateRef('el')
const {
isSupported,
animate,
// actions
play,
pause,
reverse,
finish,
cancel,
// states
pending,
playState,
replaceState,
startTime,
currentTime,
timeline,
playbackRate,
} = useAnimate(el, { transform: 'rotate(360deg)' }, 1000)
</script>
<template>
<span ref="el" style="display:inline-block">useAnimate</span>
</template>Custom Keyframes
Either an array of keyframe objects, or a keyframe object, or a ref. See Keyframe Formats for more details.
import { useAnimate } from '@vueuse/core'
import { useTemplateRef } from 'vue'
const el = useTemplateRef('el')
// ---cut---
const keyframes = { transform: 'rotate(360deg)' }
// Or
const keyframes = [
{ transform: 'rotate(0deg)' },
{ transform: 'rotate(360deg)' },
]
// Or
const keyframes = ref([
{ clipPath: 'circle(20% at 0% 30%)' },
{ clipPath: 'circle(20% at 50% 80%)' },
{ clipPath: 'circle(20% at 100% 30%)' },
])
useAnimate(el, keyframes, 1000)Options
The third argument accepts a duration number or an options object with the following additional properties on top of KeyframeAnimationOptions:
import { useAnimate } from '@vueuse/core'
useAnimate(el, keyframes, {
duration: 1000,
// Start playing immediately (default: true)
immediate: true,
// Commit the end styling state to the element (default: false)
commitStyles: false,
// Persist the animation (default: false)
persist: false,
// Callback when animation is initialized
onReady(animate) {
console.log('Animation ready', animate)
},
// Callback when an error occurs
onError(e) {
console.error('Animation error', e)
},
})Delaying Start
Set immediate: false to prevent the animation from starting automatically.
import { useAnimate } from '@vueuse/core'
const { play } = useAnimate(el, keyframes, {
duration: 1000,
immediate: false,
})
// Start the animation manually
play()Type Declarations
export interface UseAnimateOptions
extends KeyframeAnimationOptions, ConfigurableWindow {
/**
* Will automatically run play when `useAnimate` is used
*
* @default true
*/
immediate?: boolean
/**
* Whether to commits the end styling state of an animation to the element being animated
* In general, you should use `fill` option with this.
*
* @default false
*/
commitStyles?: boolean
/**
* Whether to persists the animation
*
* @default false
*/
persist?: boolean
/**
* Executed after animation initialization
*/
onReady?: (animate: Animation) => void
/**
* Callback when error is caught.
*/
onError?: (e: unknown) => void
}
export type UseAnimateKeyframes = MaybeRef<
Keyframe[] | PropertyIndexedKeyframes | null
>
export interface UseAnimateReturn extends Supportable {
animate: ShallowRef<Animation | undefined>
play: () => void
pause: () => void
reverse: () => void
finish: () => void
cancel: () => void
pending: ComputedRef<boolean>
playState: ComputedRef<AnimationPlayState>
replaceState: ComputedRef<AnimationReplaceState>
startTime: WritableComputedRef<CSSNumberish | number | null>
currentTime: WritableComputedRef<CSSNumberish | null>
timeline: WritableComputedRef<AnimationTimeline | null>
playbackRate: WritableComputedRef<number>
}
/**
* Reactive Web Animations API
*
* @see https://vueuse.org/useAnimate
* @param target
* @param keyframes
* @param options
*/
export declare function useAnimate(
target: MaybeComputedElementRef,
keyframes: UseAnimateKeyframes,
options?: number | UseAnimateOptions,
): UseAnimateReturnuseArrayDifference
Reactive get array difference of two arrays.
By default, it returns the difference of the first array from the second array, so call A \ B, Relative Complement>) of B in A.
You can pass the symmetric option to get the Symmetric difference of two arrays A △ B.
Usage
Use with reactive array
import { useArrayDifference } from '@vueuse/core'
const list1 = ref([0, 1, 2, 3, 4, 5])
const list2 = ref([4, 5, 6])
const result = useArrayDifference(list1, list2)
// result.value: [0, 1, 2, 3]
list2.value = [0, 1, 2]
// result.value: [3, 4, 5]Use with reactive array and use function comparison
import { useArrayDifference } from '@vueuse/core'
const list1 = ref([{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }])
const list2 = ref([{ id: 4 }, { id: 5 }, { id: 6 }])
const result = useArrayDifference(list1, list2, (value, othVal) => value.id === othVal.id)
// result.value: [{ id: 1 }, { id: 2 }, { id: 3 }]Symmetric Difference
This composable also supports Symmetric difference by passing the symmetric option.
```ts {10} import { useArrayDifference } from '@vueuse/core'
const list1 = ref([{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }]) const list2 = ref([{ id: 4 }, { id: 5 }, { id: 6 }])
const result = useArrayDifference( list1, list2, (value, othVal) => value.id === othVal.id, { symmetric: true } ) // result.value: [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 6 }]
## Type Declarations
export interface UseArrayDifferenceOptions { /**
- Returns asymmetric difference
*
- @see https://en.wikipedia.org/wiki/Symmetric_difference
- @default false
*/ symmetric?: boolean } export type UseArrayDifferenceReturn<T = any> = ComputedRef<T[]> export declare function useArrayDifference<T>( list: MaybeRefOrGetter<T[]>, values: MaybeRefOrGetter<T[]>, key?: keyof T, options?: UseArrayDifferenceOptions, ): UseArrayDifferenceReturn<T> export declare function useArrayDifference<T>( list: MaybeRefOrGetter<T[]>, values: MaybeRefOrGetter<T[]>, compareFn?: (value: T, othVal: T) => boolean, options?: UseArrayDifferenceOptions, ): UseArrayDifferenceReturn<T>
useArrayEvery
Reactive Array.every
Usage
Use with array of multiple refs
import { useArrayEvery } from '@vueuse/core'
const item1 = ref(0)
const item2 = ref(2)
const item3 = ref(4)
const item4 = ref(6)
const item5 = ref(8)
const list = [item1, item2, item3, item4, item5]
const result = useArrayEvery(list, i => i % 2 === 0)
// result.value: true
item1.value = 1
// result.value: falseUse with reactive array
import { useArrayEvery } from '@vueuse/core'
const list = ref([0, 2, 4, 6, 8])
const result = useArrayEvery(list, i => i % 2 === 0)
// result.value: true
list.value.push(9)
// result.value: falseType Declarations
export type UseArrayEveryReturn = ComputedRef<boolean>
/**
* Reactive `Array.every`
*
* @see https://vueuse.org/useArrayEvery
* @param list - the array was called upon.
* @param fn - a function to test each element.
*
* @returns **true** if the `fn` function returns a **truthy** value for every element from the array. Otherwise, **false**.
*
* @__NO_SIDE_EFFECTS__
*/
export declare function useArrayEvery<T>(
list: MaybeRefOrGetter<MaybeRefOrGetter<T>[]>,
fn: (element: T, index: number, array: MaybeRefOrGetter<T>[]) => unknown,
): UseArrayEveryReturnuseArrayFilter
Reactive Array.filter
Usage
Use with array of multiple refs
import { useArrayFilter } from '@vueuse/core'
const item1 = ref(0)
const item2 = ref(2)
const item3 = ref(4)
const item4 = ref(6)
const item5 = ref(8)
const list = [item1, item2, item3, item4, item5]
const result = useArrayFilter(list, i => i % 2 === 0)
// result.value: [0, 2, 4, 6, 8]
item2.value = 1
// result.value: [0, 4, 6, 8]Use with reactive array
import { useArrayFilter } from '@vueuse/core'
const list = ref([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
const result = useArrayFilter(list, i => i % 2 === 0)
// result.value: [0, 2, 4, 6, 8]
list.value.shift()
// result.value: [2, 4, 6, 8]Type Declarations
export type UseArrayFilterReturn<T = any> = ComputedRef<T[]>
/**
* Reactive `Array.filter`
*
* @see https://vueuse.org/useArrayFilter
* @param list - the array was called upon.
* @param fn - a function that is called for every element of the given `list`. Each time `fn` executes, the returned value is added to the new array.
*
* @returns a shallow copy of a portion of the given array, filtered down to just the elements from the given array that pass the test implemented by the provided function. If no elements pass the test, an empty array will be returned.
*
* @__NO_SIDE_EFFECTS__
*/
export declare function useArrayFilter<T, S extends T>(
list: MaybeRefOrGetter<MaybeRefOrGetter<T>[]>,
fn: (element: T, index: number, array: T[]) => element is S,
): UseArrayFilterReturn<S>
export declare function useArrayFilter<T>(
list: MaybeRefOrGetter<MaybeRefOrGetter<T>[]>,
fn: (element: T, index: number, array: T[]) => unknown,
): UseArrayFilterReturn<T>useArrayFind
Reactive Array.find.
Usage
import { useArrayFind } from '@vueuse/core'
const list = [ref(1), ref(-1), ref(2)]
const positive = useArrayFind(list, val => val > 0)
// positive.value: 1Use with reactive array
import { useArrayFind } from '@vueuse/core'
const list = reactive([-1, -2])
const positive = useArrayFind(list, val => val > 0)
// positive.value: undefined
list.push(1)
// positive.value: 1Type Declarations
export type UseArrayFindReturn<T = any> = ComputedRef<T | undefined>
/**
* Reactive `Array.find`
*
* @see https://vueuse.org/useArrayFind
* @param list - the array was called upon.
* @param fn - a function to test each element.
*
* @returns the first element in the array that satisfies the provided testing function. Otherwise, undefined is returned.
*
* @__NO_SIDE_EFFECTS__
*/
export declare function useArrayFind<T>(
list: MaybeRefOrGetter<MaybeRefOrGetter<T>[]>,
fn: (element: T, index: number, array: MaybeRefOrGetter<T>[]) => boolean,
): UseArrayFindReturn<T>useArrayFindIndex
Reactive Array.findIndex
Usage
Use with array of multiple refs
import { useArrayFindIndex } from '@vueuse/core'
const item1 = ref(0)
const item2 = ref(2)
const item3 = ref(4)
const item4 = ref(6)
const item5 = ref(8)
const list = [item1, item2, item3, item4, item5]
const result = useArrayFindIndex(list, i => i % 2 === 0)
// result.value: 0
item1.value = 1
// result.value: 1Use with reactive array
import { useArrayFindIndex } from '@vueuse/core'
const list = ref([0, 2, 4, 6, 8])
const result = useArrayFindIndex(list, i => i % 2 === 0)
// result.value: 0
list.value.unshift(-1)
// result.value: 1Type Declarations
export type UseArrayFindIndexReturn = ComputedRef<number>
/**
* Reactive `Array.findIndex`
*
* @see https://vueuse.org/useArrayFindIndex
* @param list - the array was called upon.
* @param fn - a function to test each element.
*
* @returns the index of the first element in the array that passes the test. Otherwise, "-1".
*
* @__NO_SIDE_EFFECTS__
*/
export declare function useArrayFindIndex<T>(
list: MaybeRefOrGetter<MaybeRefOrGetter<T>[]>,
fn: (element: T, index: number, array: MaybeRefOrGetter<T>[]) => unknown,
): UseArrayFindIndexReturnuseArrayFindLast
Reactive Array.findLast.
Usage
import { useArrayFindLast } from '@vueuse/core'
const list = [ref(1), ref(-1), ref(2)]
const positive = useArrayFindLast(list, val => val > 0)
// positive.value: 2Use with reactive array
import { useArrayFindLast } from '@vueuse/core'
const list = reactive([-1, -2])
const positive = useArrayFindLast(list, val => val > 0)
// positive.value: undefined
list.push(10)
// positive.value: 10
list.push(5)
// positive.value: 5Type Declarations
export type UseArrayFindLastReturn<T = any> = ComputedRef<T | undefined>
/**
* Reactive `Array.findLast`
*
* @see https://vueuse.org/useArrayFindLast
* @param list - the array was called upon.
* @param fn - a function to test each element.
*
* @returns the last element in the array that satisfies the provided testing function. Otherwise, undefined is returned.
*
* @__NO_SIDE_EFFECTS__
*/
export declare function useArrayFindLast<T>(
list: MaybeRefOrGetter<MaybeRefOrGetter<T>[]>,
fn: (element: T, index: number, array: MaybeRefOrGetter<T>[]) => boolean,
): UseArrayFindLastReturn<T>useArrayMap
Reactive Array.map
Usage
Use with array of multiple refs
import { useArrayMap } from '@vueuse/core'
const item1 = ref(0)
const item2 = ref(2)
const item3 = ref(4)
const item4 = ref(6)
const item5 = ref(8)
const list = [item1, item2, item3, item4, item5]
const result = useArrayMap(list, i => i * 2)
// result.value: [0, 4, 8, 12, 16]
item1.value = 1
// result.value: [2, 4, 8, 12, 16]Use with reactive array
import { useArrayMap } from '@vueuse/core'
const list = ref([0, 1, 2, 3, 4])
const result = useArrayMap(list, i => i * 2)
// result.value: [0, 2, 4, 6, 8]
list.value.pop()
// result.value: [0, 2, 4, 6]Type Declarations
export type UseArrayMapReturn<T = any> = ComputedRef<T[]>
/**
* Reactive `Array.map`
*
* @see https://vueuse.org/useArrayMap
* @param list - the array was called upon.
* @param fn - a function that is called for every element of the given `list`. Each time `fn` executes, the returned value is added to the new array.
*
* @returns a new array with each element being the result of the callback function.
*
* @__NO_SIDE_EFFECTS__
*/
export declare function useArrayMap<T, U = T>(
list: MaybeRefOrGetter<MaybeRefOrGetter<T>[]>,
fn: (element: T, index: number, array: T[]) => U,
): UseArrayMapReturn<U>