Next.js utilities for observing when elements enter or leave the viewport using Intersection Observer API.
npm install @intersection-observer/next> A performant, flexible Next.js wrapper for the Intersection Observer API.
---
- 🪝 Hook — Use useInView for reactive intersection detection in Next.js
- 🎨 Component — Use LazyRender for declarative lazy loading
- ⚡️ Optimized Performance — Reuses observer instances efficiently
- 🔧 API Match — Based on native Intersection Observer API
- 🔠 TypeScript Support — Fully typed for TS projects
- 🌳 Tree-shakeable — Only the code you use gets bundled
- 🚀 Zero Dependencies — Lightweight with no external deps
---
``bashWith pnpm
pnpm add @intersection-observer/next
---
🚀 Quick Start (Next.js)
$3
`tsx
import { useInView } from '@intersection-observer/next';export default function MyComponent() {
const { ref, inView } = useInView({ threshold: 0.5 });
return (
{inView ? 'Element is visible!' : 'Element is hidden'}
);
}
`$3
`tsx
import { LazyRender } from '@intersection-observer/next';export default function LazyImage() {
return (

);
}
`---
📚 API Reference
$3
A Next.js hook that returns a ref and boolean indicating if the element is in view.
`tsx
function useInView(options?: InViewOptions): {
ref: RefObject
inView: boolean
}
`#### Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
|
threshold | number \| number[] | 0 | Percentage of element visibility (0-1) |
| rootMargin | string | '0px' | Margin around the root (e.g., "10px 20px") |
| root | Element \| null | null | Element to use as viewport |#### Example with Options
`tsx
const { ref, inView } = useInView({
threshold: [0, 0.25, 0.5, 0.75, 1], // Multiple thresholds
rootMargin: '50px', // Trigger 50px before element enters viewport
root: document.querySelector('.scroll-container') // Custom root
});
`$3
A component that renders children only when they come into view.
`tsx
interface LazyRenderProps {
children: ReactNode | ((props: RenderProps) => ReactNode)
as?: keyof JSX.IntrinsicElements
onChange?: (inView: boolean) => void
threshold?: number
className?: string
style?: CSSProperties
}interface RenderProps {
inView: boolean
ref: (node: HTMLElement | null) => void
}
`#### Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
|
children | ReactNode \| Function | - | Content to render or render function |
| as | string | 'div' | HTML element to render |
| onChange | (inView: boolean) => void | - | Callback when visibility changes |
| threshold | number | 0 | Visibility threshold (0-1) |
| className | string | - | CSS class name |
| style | CSSProperties | - | Inline styles |---
🎯 Next.js Example
$3
`tsx
import { LazyRender } from '@intersection-observer/next';export default function ProductList({ products }) {
return (
{products.map((product) => (
{({ inView, ref }) => (
{inView && (
)}
)}
))}
);
}
`---
🌐 Browser Support
This package uses the Intersection Observer API, which is supported in all modern browsers:
- ✅ Chrome 51+
- ✅ Firefox 55+
- ✅ Safari 12.1+
- ✅ Edge 15+
For older browsers, you can use a polyfill:
`bash
npm install intersection-observer
``tsx
// Add this to your app entry point
import 'intersection-observer';
`---
🛠 Development
This package is part of a monorepo. To link it locally:
`bash
pnpm install
pnpm dev # or use your Next.js example app
``---
MIT — Made with ❤️ by Ahmed Aljohi (https://github.com/AhmedAljhoi)