Skip to content

Infinite Drag Canvas

An endlessly pannable board that recycles a fixed set of tiles via modulo wrapping.

Proplayfulbrutalistminimal
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.

Preview
AURORA
PIXEL
DEPTH
ORBIT
SWEEP
GLARE
DEPTH
ORBIT
SWEEP
GLARE
DRIFT
METAL
SWEEP
GLARE
DRIFT
METAL
RIBBON
AURORA
DRIFT
METAL
RIBBON
AURORA
PIXEL
DEPTH
RIBBON
AURORA
PIXEL
DEPTH
ORBIT
SWEEP
x 0 · y 0
Drag me

Props

92
8
Coordinate readout
No runtime dependencies
"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
  // ---------------------------------------------------------------
}
Notes

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.

Related

Pairs well with

Matched on shared tags and category — the entries most likely to be used alongside this one.

Featured
New

A rail you can throw — it projects the momentum and settles on the nearest slide.

dragcarouselinertia
Featured

A draggable deck of cards you flick away to cycle through, Tinder-style.

dragswipestack

A custom-styled slider with a drag handle and a value tooltip while dragging.

sliderrangedrag