👁️ Intersection Observer

Detect element visibility with v-intersection directive

Example 1: Scroll Detection

Use Case: Detect when elements enter or leave the viewport using IntersectionObserver API.

Hint: Scroll down to see the observable box appear!

↓ Scroll down ↓
↓ Keep scrolling ↓

Observable Element

I'm {{ isVisible ? 'VISIBLE' : 'NOT VISIBLE' }}

{{ isVisible ? '✓ Visible' : '✗ Not Visible' }}
↓ Keep scrolling ↓
End of scroll area
Is Visible: {{ isVisible }}
Intersection Ratio: {{ (intersectionRatio * 100).toFixed(1) }}%
Is Intersecting: {{ isIntersecting }}
Intersection Count: {{ intersectionCount }}
// Intersection observer with v-intersection directive
<div v-intersection="onIntersection" class="observable-box">
  I'm {{ isVisible ? 'VISIBLE' : 'NOT VISIBLE' }}
</div>

methods: {
  onIntersection(entries, $ctx) {
    const entry = entries[0];

    // Check if element is intersecting with viewport
    this.isVisible = entry.isIntersecting;
    this.intersectionRatio = entry.intersectionRatio;

    // Access element through $ctx
    console.log('Element:', $ctx.element);
    console.log('VNode:', $ctx.vnode);
  }
}

Example 2: Custom Threshold

Use Case: Configure IntersectionObserver with custom options using :options.intersection attribute.

Hint: This example triggers when 50% of the element is visible!

↓ Scroll to 50% visibility ↓

50% Threshold Observer

Triggers at {{ observerOptions.threshold * 100 }}% visibility

{{ isThresholdVisible ? '✓ 50% Visible' : '✗ Less than 50%' }}
End of scroll area
// Custom threshold with :options.intersection
<div
  v-intersection="onThresholdIntersection"
  :options.intersection="observerOptions">
  Triggers at 50% visibility
</div>

data: {
  observerOptions: {
    threshold: 0.5,
    rootMargin: '0px'
  }
},
methods: {
  onThresholdIntersection(entries, $ctx) {
    const entry = entries[0];
    this.isThresholdVisible = entry.isIntersecting;
  }
}

Key Features

  • IntersectionObserver API: Native browser API for efficient visibility detection
  • Custom Options: Configure threshold, rootMargin via :options.intersection or :options
  • Context Parameter: Access element, VNode, and userData via $ctx
  • Automatic Cleanup: Observer is disconnected during the destroy phase
  • Performance: More efficient than scroll event listeners
// Handler signature
onIntersection(entries: IntersectionObserverEntry[], $ctx: LifecycleContext) {
  // entries[0].isIntersecting - true if visible
  // entries[0].intersectionRatio - 0.0 to 1.0
  // entries[0].boundingClientRect - element position
  // $ctx.element - DOM element
  // $ctx.vnode - VNode instance
  // $ctx.userData - Proxy-free storage
}

// Options format (IntersectionObserverInit)
{
  root: null,          // viewport or ancestor element
  rootMargin: '0px',  // margin around root
  threshold: 0.5      // 0.0 to 1.0 or array of thresholds
}
← Back to Examples