CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-vueuse--components

Renderless Vue.js components that expose VueUse composable functionality through declarative template-based interfaces

Pending
Overview
Eval results
Files

mouse-pointer.mddocs/

Mouse and Pointer

Components and directives for tracking mouse and pointer interactions, positions, and states.

Capabilities

UseMouse Component

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>

UseMouseInElement Component

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>

vMouseInElement Directive

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>

UseMousePressed Component

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>

UsePointer Component

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>

Type Definitions

/** 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

docs

browser-apis.md

browser-events.md

device-sensors.md

element-tracking.md

index.md

mouse-pointer.md

scroll-resize.md

theme-preferences.md

utilities-advanced.md

window-document.md

tile.json