Skip to content
On this page

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.

  • trackingAreaEl receives 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 x and y are 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>

See Also

useClientPoint has loaded