@wikicasa-dev/components · Utilities · preferred

IntersectionObserverProvider

Shares one IntersectionObserver with its IntersectionObserverTarget children to lazy-render content or detect scroll-into-view.

import IntersectionObserverProvider from "@wikicasa-dev/components/generic/IntersectionObserver/v2/IntersectionObserverProvider";

Renderless wrapper that creates one browser IntersectionObserver (viewport as root) and shares it with every IntersectionObserverTarget inside it. Each target gets its own isVisible flag. Use the pair to:

  • render a heavy section (chart, map, carousel, list of cards) only when it scrolls into view;
  • run something when a sentinel becomes visible (infinite scroll: "load more" when the last row appears), via the provider's intersection event.

This replaces the older IntersectionObserver + IntersectionObservable pair.

Usage

Lazy section plus an infinite-scroll sentinel:

<script setup lang="ts">
import { ref } from "vue";
import IntersectionObserverProvider from "@wikicasa-dev/components/generic/IntersectionObserver/v2/IntersectionObserverProvider";
import IntersectionObserverTarget from "@wikicasa-dev/components/generic/IntersectionObserver/v2/IntersectionObserverTarget";

const listings = ref(["Bilocale a Bari", "Villa a Lecce", "Attico a Taranto"]);
const loadMore = () => listings.value.push(`Annuncio ${listings.value.length + 1}`);
</script>

<template>
  <IntersectionObserverProvider :threshold="0.1">
    <IntersectionObserverTarget v-slot="{ isVisible }">
      <section v-if="isVisible">Andamento prezzi a Bari (grafico)</section>
      <div v-else style="height: 270px" />
    </IntersectionObserverTarget>
  </IntersectionObserverProvider>

  <ul>
    <li v-for="l in listings" :key="l">{{ l }}</li>
  </ul>
  <IntersectionObserverProvider @intersection="loadMore">
    <IntersectionObserverTarget :observe-once="false">
      <p>Caricamento altri annunci…</p>
    </IntersectionObserverTarget>
  </IntersectionObserverProvider>
</template>

Do / Don't

  • Do put every IntersectionObserverTarget inside a provider; outside one, isVisible stays false forever.
  • Do reserve the final height in the not-visible branch so the page doesn't jump when content appears.
  • intersection fires every time any target enters the viewport (repeatedly for targets with :observe-once="false").
  • Use emit-once only with a single target: it disconnects the whole observer after the first intersection, so other targets never become visible.
  • Don't use skip to "show everything immediately": it ignores all intersections, so targets never become visible. To bypass lazy rendering, render your content without the provider (e.g. v-if="!lazy" / v-else).
  • threshold (0–1, share of the target that must be visible) is read once, when the provider is created.
  • Observation runs only in the browser: on the server every target renders its not-visible branch.

API

Generated from the component's types. Do not edit by hand.

Props

Name Type Default Required Description
emitOnce boolean false
skip boolean false
threshold number 0

Events

Name Payload
intersection

v-model

None.

Slots

Name Slot props
default { observer: IntersectionObserver | undefined; }

Exposed (template ref)

None.