Skip to main content
Vuetify0 is now in alpha!
Vuetify0 Logo
Theme
Mode
Palettes
Accessibility
Vuetify One
Sign in to Vuetify One

Access premium tools across the Vuetify ecosystem — Bin, Play, Studio, and more.

Not a subscriber? See what's included

useIntersectionObserver

A composable for detecting when elements enter or leave the viewport using the Intersection Observer API with automatic cleanup.


AdvancedApr 5, 2026

Usage

The useIntersectionObserver composable wraps the Intersection Observer API to detect when elements become visible in the viewport. It’s useful for lazy loading images, infinite scroll, entrance animations, and performance optimizations.

Tip

Why wrap IntersectionObserver? The native IntersectionObserver has no awareness of Vue’s effectScope lifecycle. If you create one inside a composable, it won’t automatically disconnect when the scope is disposed. useIntersectionObserver integrates onScopeDispose for automatic cleanup, defers creation until after hydration for SSR safety, and adds reactive target tracking — things the native API can’t do on its own.

vue
<script setup lang="ts">
  import { useIntersectionObserver } from '@vuetify/v0'
  import { ref, useTemplateRef } from 'vue'

  const target = useTemplateRef('target')
  const isVisible = ref(false)

  useIntersectionObserver(target, (entries) => {
    isVisible.value = entries[0].isIntersecting
  }, {
    threshold: 0.5, // Trigger when 50% visible
    rootMargin: '0px'
  })
</script>

<template>
  <div>
    <div style="height: 100vh">Scroll down to see the element</div>
    <div ref="target" :class="{ visible: isVisible }">
      I'm {{ isVisible ? 'visible' : 'hidden' }}
    </div>
  </div>
</template>

Architecture

useIntersectionObserver wraps the native IntersectionObserver API with Vue reactivity:

Intersection Observer Hierarchy

Use controls to zoom and pan. Click outside or press Escape to close.

Intersection Observer Hierarchy

Options

OptionTypeDefaultNotes
immediatebooleanfalseFire the callback immediately on mount before any intersection
oncebooleanfalseStop observing after the first intersection fires
thresholdnumber | number[]0Intersection ratio(s) at which the callback fires
rootElement | nullnullAncestor to use as viewport (null = browser viewport)
rootMarginstring'0px'CSS margin around the root for intersection calculations

Reactivity

Property/MethodReactiveNotes
isActiveComputed from observer ref
isIntersectingShallowRef, readonly
isPausedShallowRef, readonly
targetAccepts MaybeRef, watched for changes
pause()Temporarily stop observing without disconnecting
resume()Resume after pause()
stop()Disconnect the observer permanently

useElementIntersection

Property/MethodReactiveNotes
isIntersectingShallowRef, readonly
intersectionRatioShallowRef, readonly (0.0 to 1.0)

Examples

Scroll Reveal with Visibility Percentage

Cards that fade in and slide up with a staggered delay as they scroll into view, with a progress bar showing each card’s visibility percentage.

Scroll to reveal cards0/6 revealed
Scroll down to see the magic

Lazy Loading

Load images only when entering viewport

0%

Infinite Scroll

Fetch more content as users scroll

0%

Analytics

Track visibility for engagement metrics

0%

Animations

Trigger entrance animations on scroll

0%

Video Playback

Auto-play videos when visible

0%

Ad Viewability

Measure ad impressions accurately

0%
You've reached the end

API Reference

The following API details are for the useIntersectionObserver composable.

Functions

useIntersectionObserver

(target: MaybeElementRef, callback: (entries: IntersectionObserverEntry[]) => void, options?: IntersectionObserverOptions) => UseIntersectionObserverReturn

A composable that uses the Intersection Observer API to detect when an element is visible in the viewport.

useElementIntersection

(target: MaybeElementRef, options?: IntersectionObserverOptions) => UseElementIntersectionReturn

A convenience composable that uses the Intersection Observer API to detect when an element is visible in the viewport.

Options

immediate

boolean | undefined

once

boolean | undefined

root

Element | null | undefined

rootMargin

string | undefined

threshold

number | number[] | undefined

Properties

isActive

Readonly<Ref<boolean, boolean>>

Whether the observer is currently active (created and observing)

isPaused

Readonly<Ref<boolean, boolean>>

Whether the observer is currently paused

isIntersecting

Readonly<Ref<boolean, boolean>>

Whether the target element is currently intersecting with the viewport

Methods

pause

() => void

Pause observation (disconnects observer but keeps it alive)

resume

() => void

Resume observation

stop

() => void

Stop observation and clean up (destroys observer)

Was this page helpful?

© 2016-1970 Vuetify, LLC
Ctrl+/