pointer
Track the latest pointer (mouse, touch, or pen) state.
| Package | @vizejs/composable/pointer |
| Own the source | vize lib pull composable:pointer |
| Runtime exports | usePointer, toPointerKind |
| Gzip budget | 1792 B |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/composable
Import the entry directly. Call lifecycle-bound utilities inside <script setup> so cleanup follows the component scope; consult the runtime contract for this entry's SSR and hydration behavior.
import { usePointer, toPointerKind } from "@vizejs/composable/pointer";
Try it
Inspect a guide pad's actual pointer events
Read the latest accepted mouse pointer snapshot and distinguish target membership from retained coordinates.
What to observe: Move into the pad, press and release, then leave. Client coordinates and pressure follow native mouse Pointer Events; Inside changes on leaving without clearing the snapshot. Hide the pad, move elsewhere, then show it again: the removed target stops receiving events and the replacement resumes observation.
usePointer receives the reactive pad target and a fixed mouse-only snapshot filter. Its shallow readonly state records client coordinates in this iframe, pressure and the pointer identifier; it is not element-relative geometry. The default provider also accepts touch and pen snapshots; this example filters those kinds on pointerdown, pointermove and pointerup, and its native browser checks cover mouse input. Pointerleave clears Inside regardless of the snapshot filter. Hiding a target does not reset the latest snapshot. Target replacement removes old passive listeners; component scope disposal stops the target watcher. SSR exposes the initial zero snapshot, null pointer kind and false inside flag; no browser host is replaced.
Compare the initial and interacted states


Copy the example
Save this complete SFC in your Vue project. Its public imports and source are the same ones executed in the preview.
<script setup lang="ts">
import { ref, useTemplateRef } from "vue";
import { usePointer } from "@vizejs/composable/pointer";
const pad = useTemplateRef<HTMLElement>("pad");
const visible = ref(true);
const { state, isInside } = usePointer({ target: pad, pointerTypes: ["mouse"] });
</script>
<template>
<div class="composable-example">
<label class="pointer-toggle"
><input v-model="visible" type="checkbox" /> Show pointer guide pad</label
>
<section v-if="visible" ref="pad" class="pointer-pad" aria-label="Pointer guide pad">
<strong>Inspect an actual mouse pointer</strong>
<p>Move across this pad, then press and release.</p>
</section>
<output aria-live="polite">
Latest pointer: {{ state.pointerType ?? "none" }} · Inside: {{ isInside ? "yes" : "no" }} ·
Client: {{ Math.round(state.x) }}, {{ Math.round(state.y) }}
</output>
<dl>
<div>
<dt>Pressure</dt>
<dd class="pointer-pressure">{{ state.pressure }}</dd>
</div>
<div>
<dt>Pointer identifier</dt>
<dd>{{ state.pointerId }}</dd>
</div>
</dl>
<p>
These readonly values describe the latest accepted event in this iframe's client coordinates,
not the pad's local coordinates. This example records mouse snapshots only; its checks cover
mouse input.
</p>
<p>
Leaving the pad changes Inside without clearing the last snapshot. Hiding it removes its
listeners; the last snapshot remains. Showing it attaches the new pad. Server rendering starts
with zero values, no pointer kind and Inside: no.
</p>
</div>
</template>
<style scoped>
.pointer-toggle {
display: inline-flex;
align-items: center;
gap: 8px;
input {
inline-size: auto;
}
}
.pointer-pad {
min-block-size: 120px;
padding: 12px;
border: 1px solid currentColor;
border-radius: 8px;
}
</style>
Runtime contract
| Utility | Category | Stability | SSR | Hydration | Cleanup | Targets | Host globals | Uses |
|---|---|---|---|---|---|---|---|---|
usePointer |
input | experimental | deterministic-fallback | stable | caller, reactive-scope | web, desktop | window |
toPointerKind, tryOnScopeDispose |
toPointerKind |
input | experimental | safe | not-applicable | none | web, server, worker, native, desktop, terminal | — | — |
API
usePointer
Track the latest pointer (mouse, touch, or pen) state. Listens passively for pointerdown, pointermove, pointerup, and pointerleave on the reactive target and filters by device kind. Listeners are removed with the owning reactive scope; server renders expose the initial snapshot.
function usePointer(options: UsePointerOptions = {}): PointerControls
toPointerKind
Narrow a platform pointerType string to the closed PointerKind union.
function toPointerKind(value: string): PointerKind | null
Types
PointerState
Snapshot of the latest pointer event.
| Member | Type | Description |
|---|---|---|
x |
number |
Horizontal client coordinate. |
y |
number |
Vertical client coordinate. |
pressure |
number |
Normalized pressure in [0, 1]. |
pointerId |
number |
Identifier of the pointer that produced the latest event. |
tiltX |
number |
Pen tilt around the Y axis in degrees. |
tiltY |
number |
Pen tilt around the X axis in degrees. |
width |
number |
Contact geometry width in CSS pixels. |
height |
number |
Contact geometry height in CSS pixels. |
twist |
number |
Pen rotation in degrees. |
pointerType |
PointerKind | null |
Device kind; null before the first event. |
UsePointerOptions
Options for usePointer.
| Member | Type | Description |
|---|---|---|
pointerTypes? |
readonly PointerKind[] |
Device kinds to track. |
target? |
MaybeRefOrGetter<EventTarget | null | undefined> |
Event target to listen on. |
initialValue? |
Partial<PointerState> |
State exposed before any input and during server rendering. |
PointerControls
Reactive pointer state returned by usePointer.
| Member | Type | Description |
|---|---|---|
state |
Readonly<PointerState> |
Latest pointer snapshot. |
isInside |
Readonly<Ref<boolean>> |
Whether the pointer is inside the target (between enter/move and leave). |