InView
InViewEngine observes the groups inside a root element and toggles a single attribute as each one
enters or leaves the viewport. All animation is pure CSS — the engine never touches style, it
only flips data-inview-visible / data-inview-hidden, and the stylesheet does the rest through
custom properties. That keeps the JavaScript tiny and the same across every framework.
Everything below starts hidden — scroll inside the panel and each group reveals as it enters. The first card also reports its own visibility.
This card reports its own visibility
The engine emits a visibility event as the root enters and leaves the panel. Scroll it away and back to watch the counter climb.
Directional entrance
Horizontal reveals mirror automatically when the document direction is RTL.
99.9%
moves without fading — ideal for metrics
Replays on every entry
Scroll past this card and back: it re-animates, while the groups above settle after their first reveal.
Everything below starts hidden — scroll inside the panel and each group reveals as it enters. The first card also reports its own visibility.
This card reports its own visibility
The engine emits a visibility event as the root enters and leaves the panel. Scroll it away and back to watch the counter climb.
Directional entrance
Horizontal reveals mirror automatically when the document direction is RTL.
99.9%
moves without fading — ideal for metrics
Replays on every entry
Scroll past this card and back: it re-animates, while the groups above settle after their first reveal.
Usage
Give the root class="inview-root" and call useInView(ref) — the engine marks the root with
data-inview-scope itself. Inside, every data-inview group shares one visibility state, and each
node opts into an animation with data-inview-anim:
import { useRef } from 'react';
import { useInView } from '@60fps/react/inview-engine';
import { inViewAnimStyle } from '@60fps/inview';
function Section() {
const ref = useRef<HTMLDivElement>(null);
useInView(ref);
return (
<div ref={ref} className="inview-root">
<section data-inview>
<h2 data-inview-anim="fade-up">Reveal me</h2>
<p data-inview-anim="fade" style={inViewAnimStyle({ delay: 120 })}>
…then me, a touch later.
</p>
</section>
</div>
);
}
<script setup lang="ts">
import { ref } from 'vue';
import { useInView } from '@60fps/vue/inview-engine';
import { inViewAnimStyle } from '@60fps/inview';
const root = ref<HTMLElement | null>(null);
useInView(root);
</script>
<template>
<div ref="root" class="inview-root">
<section data-inview>
<h2 data-inview-anim="fade-up">Reveal me</h2>
<p data-inview-anim="fade" :style="inViewAnimStyle({ delay: 120 })">…then me, a touch later.</p>
</section>
</div>
</template>
The markup contract
| Attribute | Type | Default | Description |
|---|---|---|---|
data-inview | on a group | — | An observed group. Toggling its visibility cascades to descendants via CSS. |
data-inview-anim | fade | fade-up | fade-left | slide-up | scale-down | — | Opt a node into one animation. Inherits the group visibility state. |
data-inview-repeat | on a group | — | Replay every time the group re-enters, instead of settling after the first reveal. |
data-inview-defer | on a group | — | Skip the enter animation for content already on screen at mount; animate only on later entries. |
data-inview-threshold | number | 0 | Per-group IntersectionObserver threshold override. |
data-inview-margin | string | '0px 0px -10% 0px' | Per-group rootMargin override. |
useInView(ref, options?)
| Option | Type | Default | Description |
|---|---|---|---|
threshold | number | number[] | 0 | Threshold for the root-level `onVisibilityChange`. |
rootMargin | string | — | Root margin for the root-level `onVisibilityChange`. |
root | Element | Document | null | — | IntersectionObserver root for the observed groups. Defaults to the viewport. |
onVisibilityChange | (visible, entry) => void | — | Called as the root element enters and leaves the viewport. Opts the root into observation. |
Tuning with inViewAnimStyle
For per-node delays, offsets or one-off overrides, inViewAnimStyle returns a plain style object
(React style or Vue :style) that sets the underlying custom properties:
inViewAnimStyle({ delay: 120, duration: 600, fromTranslateY: '28px' });
// → { '--inview-delay': '120ms', '--inview-duration': '600ms', '--inview-from-translate-y': '28px' }