Appearance
useClientPoint
useClientPoint positions a floating element relative to pointer coordinates by swapping the floating context anchor for a virtual element.
Type
ts
function useClientPoint(
context: UseClientPointContext,
options: UseClientPointOptions,
): UseClientPointReturn;
interface UseClientPointOptions {
trackingAreaEl?: Ref<HTMLElement | null>;
enabled?: MaybeRefOrGetter<boolean>;
x?: MaybeRefOrGetter<number | null>;
y?: MaybeRefOrGetter<number | null>;
trackingMode?: "follow" | "static";
}
interface UseClientPointReturn {
coordinates: Readonly<Ref<{ x: number | null; y: number | null }>>;
updatePosition: (x: number, y: number) => void;
}Details
useClientPoint is centered on the floating root. Pass the floating context first. By default, pointer tracking listens on document.documentElement. Pass options.trackingAreaEl when tracking should be scoped to a specific element.
trackingAreaElreceives pointer listeners and provides fallback geometry for the virtual anchor.trackingMode: "follow"keeps the floating element in sync with pointer movement.trackingMode: "static"captures the initial point and keeps the surface anchored there.- If both
xandyare provided, the composable behaves like a controlled source of coordinates.
Example
This example shows the root-first overload.
vue
<script setup lang="ts">
import { ref } from "vue";
import { useClientPoint, useFloatingContext, usePosition, useHover } from "v-float";
const trackingAreaEl = ref<HTMLElement | null>(null);
const anchorEl = ref<HTMLElement | null>(null);
const floatingEl = ref<HTMLElement | null>(null);
const context = useFloatingContext({ refs: { anchorEl, floatingEl } });
const { styles } = usePosition(context, {
placement: "right-start",
});
useClientPoint(context, {
trackingAreaEl,
});
useHover(context);
</script>
<template>
<div ref="trackingAreaEl">
Move the pointer here
<div v-if="context.state.open.value" ref="floatingEl" :style="styles">
Tooltip follows the pointer
</div>
</div>
</template>