Renderless Vue.js components that expose VueUse composable functionality through declarative template-based interfaces
—
Components and directives for tracking mouse and pointer interactions, positions, and states.
Tracks mouse position and state with reactive updates.
/**
* Component that tracks mouse position and state
* @example
* <UseMouse v-slot="{ x, y, sourceType }">
* <div>Mouse: {{ x }}, {{ y }} ({{ sourceType }})</div>
* </UseMouse>
*/
interface UseMouseProps {
/** Mouse position coordinate type @default 'page' */
type?: UseMouseCoordType | UseMouseEventExtractor;
/** Listen events on target element @default window */
target?: MaybeRefOrGetter<Window | EventTarget | null | undefined>;
/** Listen to touchmove events @default true */
touch?: boolean;
/** Listen to scroll events on window @default true */
scroll?: boolean;
/** Reset to initial value when touchend event fired @default false */
resetOnTouchEnds?: boolean;
/** Initial position values */
initialValue?: Position;
/** Event filter for throttling/debouncing */
eventFilter?: EventFilter;
/** Window object @default defaultWindow */
window?: Window;
}
/** Slot data exposed by UseMouse component */
interface UseMouseReturn {
/** Current x position */
x: Ref<number>;
/** Current y position */
y: Ref<number>;
/** Source type of the last position update */
sourceType: Ref<UseMouseSourceType>;
}
type UseMouseCoordType = 'page' | 'client' | 'screen' | 'movement';
type UseMouseSourceType = 'mouse' | 'touch' | null;
type UseMouseEventExtractor = (event: MouseEvent | Touch) => [x: number, y: number] | null | undefined;
interface Position {
x: number;
y: number;
}Usage Examples:
<template>
<!-- Basic mouse tracking -->
<UseMouse v-slot="{ x, y, sourceType }">
<div class="mouse-tracker">
<p>Position: ({{ Math.round(x) }}, {{ Math.round(y) }})</p>
<p>Source: {{ sourceType || 'none' }}</p>
</div>
</UseMouse>
<!-- Client coordinates -->
<UseMouse type="client" v-slot="{ x, y }">
<div>Client position: {{ Math.round(x) }}, {{ Math.round(y) }}</div>
</UseMouse>
<!-- Movement tracking -->
<UseMouse type="movement" v-slot="{ x, y }">
<div>Movement delta: {{ x }}, {{ y }}</div>
</UseMouse>
<!-- Touch disabled -->
<UseMouse :touch="false" v-slot="{ x, y, sourceType }">
<div>Mouse only (no touch): {{ x }}, {{ y }} ({{ sourceType }})</div>
</UseMouse>
<!-- Custom initial value -->
<UseMouse
:initial-value="{ x: 100, y: 100 }"
v-slot="{ x, y }"
>
<div>Starts at 100,100: {{ x }}, {{ y }}</div>
</UseMouse>
</template>
<script setup>
import { UseMouse } from '@vueuse/components';
</script>Tracks mouse position relative to a specific element.
/**
* Component that tracks mouse position within element bounds
* @example
* <UseMouseInElement v-slot="{ x, y, isOutside }">
* <div>Relative: {{ x }}, {{ y }} Outside: {{ isOutside }}</div>
* </UseMouseInElement>
*/
interface UseMouseInElementProps extends RenderableComponent {
/** Handle outside element @default true */
handleOutside?: boolean;
/** Mouse position coordinate type @default 'page' */
type?: UseMouseCoordType | UseMouseEventExtractor;
/** Listen to touchmove events @default true */
touch?: boolean;
/** Reset to initial value when touchend event fired @default false */
resetOnTouchEnds?: boolean;
/** Initial position values */
initialValue?: Position;
/** Event filter for throttling/debouncing */
eventFilter?: EventFilter;
/** Window object @default defaultWindow */
window?: Window;
}
/** Slot data exposed by UseMouseInElement component */
interface UseMouseInElementReturn {
/** Current x position relative to element */
x: Ref<number>;
/** Current y position relative to element */
y: Ref<number>;
/** Source type of the last position update */
sourceType: Ref<UseMouseSourceType>;
/** Whether mouse is outside the element */
isOutside: Ref<boolean>;
/** Element width */
elementWidth: Ref<number>;
/** Element height */
elementHeight: Ref<number>;
/** Element x position */
elementX: Ref<number>;
/** Element y position */
elementY: Ref<number>;
/** Element position and size info */
elementPositionX: Ref<number>;
elementPositionY: Ref<number>;
/** Stop tracking */
stop: () => void;
}Usage Examples:
<template>
<!-- Basic relative positioning -->
<UseMouseInElement v-slot="{ x, y, isOutside }">
<div class="mouse-area" :class="{ outside: isOutside }">
<p>Mouse position in element: {{ Math.round(x) }}, {{ Math.round(y) }}</p>
<p>{{ isOutside ? 'Outside' : 'Inside' }} element</p>
</div>
</UseMouseInElement>
<!-- All data -->
<UseMouseInElement v-slot="{ x, y, elementWidth, elementHeight, elementX, elementY, stop }">
<div class="detailed-area">
<h3>Mouse in Element Details</h3>
<p>Mouse: ({{ Math.round(x) }}, {{ Math.round(y) }})</p>
<p>Element size: {{ Math.round(elementWidth) }} × {{ Math.round(elementHeight) }}</p>
<p>Element position: ({{ Math.round(elementX) }}, {{ Math.round(elementY) }})</p>
<button @click="stop">Stop tracking</button>
</div>
</UseMouseInElement>
<!-- Handle outside disabled -->
<UseMouseInElement :handle-outside="false" v-slot="{ x, y, isOutside }">
<div class="no-outside-tracking">
Position: {{ x }}, {{ y }} (Outside tracking: disabled)
</div>
</UseMouseInElement>
</template>
<script setup>
import { UseMouseInElement } from '@vueuse/components';
</script>
<style>
.mouse-area, .detailed-area, .no-outside-tracking {
width: 300px;
height: 200px;
border: 2px solid #ccc;
padding: 20px;
margin: 20px 0;
background: #f9f9f9;
}
.outside {
background: #ffebee;
border-color: #f44336;
}
</style>Directive for mouse-in-element tracking without component wrapper.
/**
* Directive for tracking mouse position within element
* @example
* <div v-mouse-in-element="handleMouse">Track mouse</div>
* <div v-mouse-in-element="[handleMouse, options]">With options</div>
*/
type MouseInElementHandler = (state: UseMouseInElementReturn) => void;
interface VMouseInElementValue {
/** Simple handler function */
handler: MouseInElementHandler;
/** Handler with options tuple */
handlerWithOptions: [MouseInElementHandler, UseMouseInElementOptions];
}
interface UseMouseInElementOptions {
/** Handle outside element @default true */
handleOutside?: boolean;
/** Mouse position coordinate type @default 'page' */
type?: UseMouseCoordType | UseMouseEventExtractor;
/** Listen to touchmove events @default true */
touch?: boolean;
/** Reset to initial value when touchend event fired @default false */
resetOnTouchEnds?: boolean;
/** Initial position values */
initialValue?: Position;
/** Event filter for throttling/debouncing */
eventFilter?: EventFilter;
/** Window object @default defaultWindow */
window?: Window;
}Usage Examples:
<template>
<!-- Simple tracking -->
<div v-mouse-in-element="handleMouse" class="tracking-element">
Mouse tracking element
</div>
<!-- With options -->
<div v-mouse-in-element="[handleMouse, { handleOutside: false, type: 'client' }]">
Client coordinates, no outside tracking
</div>
</template>
<script setup>
import { vMouseInElement } from '@vueuse/components';
function handleMouse(state) {
console.log('Mouse state:', {
x: state.x.value,
y: state.y.value,
isOutside: state.isOutside.value,
elementSize: {
width: state.elementWidth.value,
height: state.elementHeight.value
}
});
}
</script>Tracks mouse button press states.
/**
* Component that tracks mouse button press state
* @example
* <UseMousePressed v-slot="{ pressed, sourceType }">
* <div>Pressed: {{ pressed }} ({{ sourceType }})</div>
* </UseMousePressed>
*/
interface UseMousePressedProps {
/** Touch support @default true */
touch?: boolean;
/** Drag support @default true */
drag?: boolean;
/** Capture events on window @default true */
capture?: boolean;
/** Initial pressed state @default false */
initialValue?: boolean;
/** Target element @default window */
target?: MaybeRefOrGetter<EventTarget | null | undefined>;
/** Window object @default defaultWindow */
window?: Window;
}
/** Slot data exposed by UseMousePressed component */
interface UseMousePressedReturn {
/** Whether any mouse button is pressed */
pressed: Ref<boolean>;
/** Source type of the press */
sourceType: Ref<UseMouseSourceType>;
}Usage Examples:
<template>
<!-- Basic press tracking -->
<UseMousePressed v-slot="{ pressed, sourceType }">
<div class="press-tracker" :class="{ pressed }">
<p>{{ pressed ? 'PRESSED' : 'Not pressed' }}</p>
<p>Source: {{ sourceType || 'none' }}</p>
</div>
</UseMousePressed>
<!-- No touch support -->
<UseMousePressed :touch="false" v-slot="{ pressed }">
<div>Mouse only pressed: {{ pressed }}</div>
</UseMousePressed>
<!-- No drag support -->
<UseMousePressed :drag="false" v-slot="{ pressed, sourceType }">
<div>No drag tracking: {{ pressed }} ({{ sourceType }})</div>
</UseMousePressed>
</template>
<script setup>
import { UseMousePressed } from '@vueuse/components';
</script>
<style>
.press-tracker {
width: 200px;
height: 100px;
border: 2px solid #ccc;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: #f9f9f9;
user-select: none;
cursor: pointer;
}
.press-tracker.pressed {
background: #e3f2fd;
border-color: #2196f3;
}
</style>Tracks pointer events supporting mouse, touch, and pen input.
/**
* Component that tracks pointer events (mouse/touch/pen)
* @example
* <UsePointer v-slot="{ x, y, pointerType, pressure }">
* <div>{{ pointerType }}: {{ x }}, {{ y }} Pressure: {{ pressure }}</div>
* </UsePointer>
*/
interface UsePointerProps {
/** Target element @default window */
target?: MaybeRefOrGetter<EventTarget | null | undefined>;
/** Pointer types to capture @default ['mouse', 'touch', 'pen'] */
pointerTypes?: PointerType[];
/** Initial position values */
initialValue?: Position;
/** Window object @default defaultWindow */
window?: Window;
}
/** Slot data exposed by UsePointer component */
interface UsePointerReturn {
/** Whether pointer is pressed */
isInside: Ref<boolean>;
/** Pressure of the pointer input */
pressure: Ref<number>;
/** Type of pointer */
pointerType: Ref<PointerType>;
/** Current x position */
x: Ref<number>;
/** Current y position */
y: Ref<number>;
}
type PointerType = 'mouse' | 'touch' | 'pen';Usage Examples:
<template>
<!-- Full pointer tracking -->
<UsePointer v-slot="{ x, y, pointerType, pressure, isInside }">
<div class="pointer-area" :class="{ inside: isInside }">
<h3>Pointer Information</h3>
<p>Position: {{ Math.round(x) }}, {{ Math.round(y) }}</p>
<p>Type: {{ pointerType }}</p>
<p>Pressure: {{ pressure.toFixed(3) }}</p>
<p>Inside: {{ isInside ? 'Yes' : 'No' }}</p>
</div>
</UsePointer>
<!-- Only pen input -->
<UsePointer :pointer-types="['pen']" v-slot="{ x, y, pressure }">
<div class="pen-area">
Pen only: {{ x }}, {{ y }} (Pressure: {{ pressure }})
</div>
</UsePointer>
<!-- Mouse and touch only -->
<UsePointer :pointer-types="['mouse', 'touch']" v-slot="{ pointerType, isInside }">
<button class="pointer-button" :class="{ active: isInside }">
{{ pointerType || 'No' }} pointer {{ isInside ? 'over' : 'away' }}
</button>
</UsePointer>
</template>
<script setup>
import { UsePointer } from '@vueuse/components';
</script>
<style>
.pointer-area, .pen-area {
width: 300px;
height: 200px;
border: 2px solid #ccc;
padding: 20px;
margin: 20px 0;
background: #f9f9f9;
touch-action: none;
}
.pointer-area.inside {
background: #e8f5e8;
border-color: #4caf50;
}
.pointer-button {
padding: 20px;
border: 2px solid #ccc;
background: #f9f9f9;
cursor: pointer;
}
.pointer-button.active {
background: #e3f2fd;
border-color: #2196f3;
}
</style>/** Common types used across mouse and pointer components */
type MaybeRefOrGetter<T> = T | Ref<T> | (() => T);
interface Position {
x: number;
y: number;
}
interface RenderableComponent {
/** The element that the component should be rendered as @default 'div' */
as?: object | string;
}
/** Pointer and mouse types */
type PointerType = 'mouse' | 'touch' | 'pen';
type UseMouseSourceType = 'mouse' | 'touch' | null;
type UseMouseCoordType = 'page' | 'client' | 'screen' | 'movement';
/** Event filter for throttling/debouncing */
interface EventFilter {
(invoke: () => void, options: any): void;
}
/** Mouse event extractor function type */
type UseMouseEventExtractor = (event: MouseEvent | Touch) => [x: number, y: number] | null | undefined;Install with Tessl CLI
npx tessl i tessl/npm-vueuse--components