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

element-tracking.mddocs/

Element Tracking

Components and directives for tracking element properties like size, position, visibility, and bounding rectangles.

Capabilities

UseElementBounding Component

Tracks element bounding rectangle information with reactive updates.

/**
 * Component that tracks element bounding rectangle
 * @example
 * <UseElementBounding v-slot="{ x, y, width, height }">
 *   <div>Position: {{ x }}, {{ y }} Size: {{ width }}x{{ height }}</div>
 * </UseElementBounding>
 */
interface UseElementBoundingProps extends RenderableComponent {
  /** ResizeObserver box type @default 'content-box' */
  box?: ResizeObserverBoxOptions;
}

/** Slot data exposed by UseElementBounding component */
interface UseElementBoundingReturn {
  /** Distance from left edge of viewport */
  x: Ref<number>;
  /** Distance from top edge of viewport */
  y: Ref<number>;
  /** Distance from top edge of viewport (alias for y) */
  top: Ref<number>;
  /** Distance from right edge of viewport */
  right: Ref<number>;
  /** Distance from bottom edge of viewport */
  bottom: Ref<number>;
  /** Distance from left edge of viewport (alias for x) */
  left: Ref<number>;
  /** Element width */
  width: Ref<number>;
  /** Element height */
  height: Ref<number>;
  /** Update the bounding information manually */
  update: () => void;
}

type ResizeObserverBoxOptions = 'border-box' | 'content-box' | 'device-pixel-content-box';

Usage Examples:

<template>
  <!-- Basic usage -->
  <UseElementBounding v-slot="{ x, y, width, height }">
    <div class="box">
      Position: ({{ Math.round(x) }}, {{ Math.round(y) }})
      <br>
      Size: {{ Math.round(width) }} × {{ Math.round(height) }}
    </div>
  </UseElementBounding>

  <!-- Access all properties -->
  <UseElementBounding v-slot="{ top, right, bottom, left, width, height, update }">
    <div class="element">
      <p>Bounding Rectangle:</p>
      <ul>
        <li>Top: {{ Math.round(top) }}px</li>
        <li>Right: {{ Math.round(right) }}px</li>
        <li>Bottom: {{ Math.round(bottom) }}px</li>
        <li>Left: {{ Math.round(left) }}px</li>
        <li>Width: {{ Math.round(width) }}px</li>
        <li>Height: {{ Math.round(height) }}px</li>
      </ul>
      <button @click="update">Manual Update</button>
    </div>
  </UseElementBounding>

  <!-- Custom wrapper element -->
  <UseElementBounding as="section" v-slot="{ width, height }">
    <div>Section size: {{ width }} × {{ height }}</div>
  </UseElementBounding>
</template>

<script setup>
import { UseElementBounding } from '@vueuse/components';
</script>

vElementBounding Directive

Directive for element bounding tracking without component wrapper.

/**
 * Directive for tracking element bounding rectangle
 * @example
 * <div v-element-bounding="handleBounding">Track bounding</div>
 * <div v-element-bounding="[handleBounding, options]">With options</div>
 */
type ElementBoundingHandler = (rect: UseElementBoundingReturn) => void;

interface VElementBoundingValue {
  /** Simple handler function */
  handler: ElementBoundingHandler;
  /** Handler with options tuple */
  handlerWithOptions: [ElementBoundingHandler, UseResizeObserverOptions];
}

interface UseResizeObserverOptions {
  /** ResizeObserver box type @default 'content-box' */
  box?: ResizeObserverBoxOptions;
}

Usage Examples:

<template>
  <!-- Simple tracking -->
  <div v-element-bounding="handleBounding" class="tracked-element">
    Tracked element
  </div>

  <!-- With options -->
  <div v-element-bounding="[handleBounding, { box: 'border-box' }]">
    Border-box tracking
  </div>
</template>

<script setup>
import { vElementBounding } from '@vueuse/components';

function handleBounding(rect) {
  console.log('Element bounds:', {
    x: rect.x.value,
    y: rect.y.value,
    width: rect.width.value,
    height: rect.height.value
  });
}
</script>

UseElementSize Component

Tracks element dimensions with reactive updates.

/**
 * Component that tracks element size
 * @example
 * <UseElementSize v-slot="{ width, height }">
 *   <div>Size: {{ width }}x{{ height }}</div>
 * </UseElementSize>
 */
interface UseElementSizeProps extends RenderableComponent {
  /** Initial size values */
  initialSize?: { width: number; height: number };
  /** ResizeObserver box type @default 'content-box' */
  box?: ResizeObserverBoxOptions;
}

/** Slot data exposed by UseElementSize component */
interface UseElementSizeReturn {
  /** Element width */
  width: Ref<number>;
  /** Element height */
  height: Ref<number>;
  /** Stop watching for size changes */
  stop: () => void;
}

Usage Examples:

<template>
  <!-- Basic usage -->
  <UseElementSize v-slot="{ width, height }">
    <div class="resizable">
      Current size: {{ Math.round(width) }} × {{ Math.round(height) }}
    </div>
  </UseElementSize>

  <!-- With initial size -->
  <UseElementSize 
    v-slot="{ width, height, stop }" 
    :initial-size="{ width: 300, height: 200 }"
  >
    <textarea 
      :style="{ width: width + 'px', height: height + 'px' }"
      @focus="() => {}"
      @blur="stop"
    >
      Resizable textarea
    </textarea>
  </UseElementSize>

  <!-- Custom box type -->
  <UseElementSize box="border-box" v-slot="{ width, height }">
    <div class="border-tracked">
      Border-box size: {{ width }} × {{ height }}
    </div>
  </UseElementSize>
</template>

<script setup>
import { UseElementSize } from '@vueuse/components';
</script>

vElementSize Directive

Directive for element size tracking without component wrapper.

/**
 * Directive for tracking element size
 * @example
 * <div v-element-size="handleSize">Track size</div>
 * <div v-element-size="[handleSize, options]">With options</div>
 */
type ElementSizeHandler = (size: UseElementSizeReturn) => void;

interface VElementSizeValue {
  /** Simple handler function */
  handler: ElementSizeHandler;
  /** Handler with options tuple */
  handlerWithOptions: [ElementSizeHandler, UseElementSizeOptions];
}

interface UseElementSizeOptions {
  /** Initial size values */
  initialSize?: { width: number; height: number };
  /** ResizeObserver box type @default 'content-box' */
  box?: ResizeObserverBoxOptions;
}

Usage Examples:

<template>
  <!-- Simple tracking -->
  <div v-element-size="handleSize" class="size-tracked">
    Size tracked element
  </div>

  <!-- With options -->
  <div v-element-size="[handleSize, { box: 'border-box', initialSize: { width: 100, height: 100 } }]">
    Custom size tracking
  </div>
</template>

<script setup>
import { vElementSize } from '@vueuse/components';

function handleSize(size) {
  console.log('Element size changed:', {
    width: size.width.value,
    height: size.height.value
  });
}
</script>

UseElementVisibility Component

Tracks element visibility within the viewport using Intersection Observer.

/**
 * Component that tracks element visibility in viewport
 * @example
 * <UseElementVisibility v-slot="{ isVisible }">
 *   <div>Visible: {{ isVisible }}</div>
 * </UseElementVisibility>
 */
interface UseElementVisibilityProps extends RenderableComponent {
  /** Intersection observer options */
  options?: IntersectionObserverInit;
  /** Scroll target element @default window */
  scrollTarget?: MaybeRefOrGetter<HTMLElement | null | undefined>;
}

/** Slot data exposed by UseElementVisibility component */
interface UseElementVisibilityReturn {
  /** Whether the element is visible in viewport */
  isVisible: Ref<boolean>;
  /** Stop the visibility observer */
  stop: () => void;
}

interface IntersectionObserverInit {
  /** Root element for intersection @default null */
  root?: Element | null;
  /** Root margin @default '0px' */
  rootMargin?: string;
  /** Visibility threshold @default 0 */
  threshold?: number | number[];
}

Usage Examples:

<template>
  <!-- Basic visibility tracking -->
  <UseElementVisibility v-slot="{ isVisible }">
    <div class="tracked-element" :class="{ visible: isVisible }">
      {{ isVisible ? 'I am visible!' : 'I am hidden' }}
    </div>
  </UseElementVisibility>

  <!-- With custom threshold -->
  <UseElementVisibility 
    v-slot="{ isVisible, stop }" 
    :options="{ threshold: 0.5 }"
  >
    <div class="half-visible">
      {{ isVisible ? '50% visible' : 'Less than 50% visible' }}
      <button @click="stop">Stop tracking</button>
    </div>
  </UseElementVisibility>

  <!-- With root margin -->
  <UseElementVisibility 
    v-slot="{ isVisible }"
    :options="{ rootMargin: '100px' }"
  >
    <div class="early-trigger">
      Triggers 100px before entering viewport: {{ isVisible }}
    </div>
  </UseElementVisibility>
</template>

<script setup>
import { UseElementVisibility } from '@vueuse/components';
</script>

<style>
.tracked-element {
  padding: 20px;
  background: #f0f0f0;
  transition: background 0.3s;
}

.tracked-element.visible {
  background: #90EE90;
}
</style>

vElementVisibility Directive

Directive for element visibility tracking without component wrapper.

/**
 * Directive for tracking element visibility in viewport
 * @example
 * <div v-element-visibility="handleVisibility">Track visibility</div>
 * <div v-element-visibility="[handleVisibility, options]">With options</div>
 */
type ElementVisibilityHandler = (isVisible: boolean, entry: IntersectionObserverEntry) => void;

interface VElementVisibilityValue {
  /** Simple handler function */
  handler: ElementVisibilityHandler;
  /** Handler with options tuple */
  handlerWithOptions: [ElementVisibilityHandler, UseElementVisibilityOptions];
}

interface UseElementVisibilityOptions {
  /** Intersection observer options */
  options?: IntersectionObserverInit;
  /** Scroll target element @default window */
  scrollTarget?: MaybeRefOrGetter<HTMLElement | null | undefined>;
}

Usage Examples:

<template>
  <!-- Simple visibility tracking -->
  <div v-element-visibility="handleVisibility" class="visibility-tracked">
    Visibility tracked element
  </div>

  <!-- With threshold -->
  <div v-element-visibility="[handleVisibility, { options: { threshold: 0.8 } }]">
    80% visibility required
  </div>

  <!-- Multiple thresholds -->
  <div v-element-visibility="[handleMultipleVisibility, { 
    options: { threshold: [0, 0.25, 0.5, 0.75, 1.0] }
  }]">
    Progressive visibility tracking
  </div>
</template>

<script setup>
import { vElementVisibility } from '@vueuse/components';

function handleVisibility(isVisible, entry) {
  console.log('Element visibility changed:', isVisible);
  console.log('Intersection ratio:', entry.intersectionRatio);
}

function handleMultipleVisibility(isVisible, entry) {
  const ratio = Math.round(entry.intersectionRatio * 100);
  console.log(`Element is ${ratio}% visible`);
}
</script>

vElementHover Directive

Directive for hover state detection on elements.

/**
 * Directive for detecting hover state on elements
 * @example
 * <div v-element-hover="handleHover">Hover me</div>
 * <div v-element-hover="[handleHover, options]">With options</div>
 */
type ElementHoverHandler = (isHovering: boolean) => void;

interface VElementHoverValue {
  /** Simple handler function */
  handler: ElementHoverHandler;
  /** Handler with options tuple */
  handlerWithOptions: [ElementHoverHandler, UseElementHoverOptions];
}

interface UseElementHoverOptions {
  /** Delay in ms before triggering hover @default 0 */
  delayEnter?: number;
  /** Delay in ms before removing hover @default 0 */
  delayLeave?: number;
}

Usage Examples:

<template>
  <!-- Simple hover detection -->
  <div v-element-hover="handleHover" class="hover-element">
    {{ isHovering ? 'Hovering!' : 'Not hovering' }}
  </div>

  <!-- With delays -->
  <div v-element-hover="[handleDelayedHover, { delayEnter: 200, delayLeave: 500 }]">
    Delayed hover (200ms enter, 500ms leave)
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { vElementHover } from '@vueuse/components';

const isHovering = ref(false);

function handleHover(hovering) {
  isHovering.value = hovering;
  console.log('Hover state:', hovering);
}

function handleDelayedHover(hovering) {
  console.log('Delayed hover state:', hovering);
}
</script>

Type Definitions

/** Common types used across element tracking */
type MaybeRefOrGetter<T> = T | Ref<T> | (() => T);
type MaybeElementRef = HTMLElement | null | undefined;

interface RenderableComponent {
  /** The element that the component should be rendered as @default 'div' */
  as?: object | string;
}

/** Position information */
interface Position {
  x: number;
  y: number;
}

/** Size information */
interface Size {
  width: number;
  height: number;
}

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