Infinite Drag Canvas
An endlessly pannable board that recycles a fixed set of tiles via modulo wrapping.
- Category
- Patterns
- Added
- 2026-09-20
- Deps
- none
- Updated
- 2026-09-20
This is a viberdy Pro component
The live preview, the props panel and the write-up are open to everyone. The full source, the AI prompt and CLI install are part of Pro.
Props
"use client";
import { useRef, useState, type ReactNode } from "react";
export function InfiniteDragCanvas({
renderTile,
tile = 92,
gap = 8,
cols = 6,
rows = 5,
showCoords = true,
}: {
/** Given a logical cell coordinate, return its content. */
renderTile: (col: number, row: number) => ReactNode;
tile?: number;
gap?: number;
cols?: number;
rows?: number;
// ---------------------------------------------------------------
// Full source available with a viberdy Pro subscription.
// https://viberdy.dev/pricing
// ---------------------------------------------------------------
}About this pattern
An infinite canvas sounds like it needs infinite elements, and the version most people write does exactly that: append tiles as the user pans until the page stops responding. The cheap alternative is to notice that you only ever see a screen's worth. Keep the pan offset unbounded, but translate a fixed grid by that offset wrapped into a single cell pitch, and the tiles recycle continuously — the board pans forever while the node count never changes. Passing the current logical cell coordinate to the tile renderer is what keeps content stable per position rather than shuffling as nodes are reused. Two smaller traps are worth naming. JavaScript's modulo returns a negative result for negative operands, so a single `%` leaves a visible gap the moment you pan up or left; the double-modulo form is required. And the gesture uses pointer events with capture, which keeps the drag alive when the pointer leaves the element and provides touch support with no separate handlers — `touch-none` then stops the browser claiming the gesture for page scrolling.
Curator’s note
Built for viberdy 2.1. Modulo wrapping with a recycled node set — the naive append-as-you-pan version dies after a few screens.
Pairs well with
Matched on shared tags and category — the entries most likely to be used alongside this one.
Drag Inertia Carousel
patternsA rail you can throw — it projects the momentum and settles on the nearest slide.
Swipe Card Stack
patternsA draggable deck of cards you flick away to cycle through, Tinder-style.
Draggable Range Slider
componentsA custom-styled slider with a drag handle and a value tooltip while dragging.