infinite-web
v0.1.0
Published
React component for infinitely looping vertical scroll.
Maintainers
Readme
infinite-web
React component for infinitely looping vertical scroll. Wrap any components — they repeat seamlessly as the user scrolls. No scrollbar, no end.
Install
npm install infinite-webReact 18+ is required as a peer dependency.
Quick start
import { InfiniteWeb } from 'infinite-web'
export default function App() {
return (
<InfiniteWeb style={{ width: '100%', height: '100vh' }}>
<SectionOne />
<SectionTwo />
<SectionThree />
</InfiniteWeb>
)
}Scroll with the mouse wheel or swipe vertically on touch devices. The children repeat endlessly in a seamless loop.
The container must have a defined height (
100vh,500px, etc.) for the scroll to work.
Props
order
Controls the sequence of children within each loop cycle.
| Value | Behaviour |
|---|---|
| "ordered" | Children appear in the order they are written. Default. |
| "reversed" | Children appear in reverse order. |
| "shuffle" | Children are shuffled with a fixed seed — same order every session. |
| "random" | Children are shuffled once on mount — different order each page load. |
| (a, b) => number | Custom comparator. Receives child indices (0-based), same signature as Array.sort. |
// Random order each page load
<InfiniteWeb order="random">...</InfiniteWeb>
// Custom sort by your own data
<InfiniteWeb order={(a, b) => priority[a] - priority[b]}>
...
</InfiniteWeb>onProgress
Callback fired on every scroll tick. Receives a number between 0 and 1 representing how far through one full cycle the user has scrolled. Resets to 0 on each loop.
<InfiniteWeb onProgress={(p) => console.log(`${Math.round(p * 100)}% through cycle`)}>
...
</InfiniteWeb>Useful for syncing UI elements (progress bars, fade effects, counters) to the scroll position.
className / style
Standard React props passed to the outer container div.
Full example
import { InfiniteWeb } from 'infinite-web'
const quotes = [
{ text: 'Stay hungry, stay foolish.', author: 'Steve Jobs' },
{ text: 'The only way to do great work is to love what you do.', author: 'Steve Jobs' },
{ text: 'In the middle of difficulty lies opportunity.', author: 'Albert Einstein' },
]
function QuoteCard({ text, author }: { text: string; author: string }) {
return (
<div style={{ height: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<blockquote>
<p>{text}</p>
<footer>— {author}</footer>
</blockquote>
</div>
)
}
export default function App() {
return (
<InfiniteWeb
order="random"
onProgress={(p) => console.log(p)}
style={{ width: '100%', height: '100vh' }}
>
{quotes.map((q, i) => (
<QuoteCard key={i} {...q} />
))}
</InfiniteWeb>
)
}How it works
InfiniteWeb renders your children multiple times end-to-end in a vertically stacked layer. The number of copies is computed from the container and content heights so the viewport is always covered. Scroll offset is tracked in a ref and applied as a CSS translateY transform — no React state is touched on scroll, keeping it fast. The offset is kept in the range [0, cycleHeight) with modulo arithmetic, creating a seamless loop.
License
MIT
