Skip to content

Ripple Roll Button

A label that rolls letter by letter to a second copy, rippling outward from wherever your pointer came in — and settling back toward where it left.

DOM + CSS0 deps1 file · 7 KB TSXreduced-motion aware

Proeditorialminimalplayful
Preview

Props

26
640

The source is part of Pro

$27/month or $179 once. See Pro

No runtime dependencies
"use client";

import { useRef, useState } from "react";

/**
 * A button whose label rolls letter by letter to a second copy of itself — and
 * the roll ripples outward from the letter nearest where the pointer came in,
 * instead of always sweeping left to right.
 *
 * THE DELAY IS DISTANCE FROM THE ORIGIN, NOT INDEX. Each letter waits
 * |i - origin| x stagger before it moves. Enter at the right-hand end and the
 * roll starts there; enter in the middle and it spreads both ways. Leaving
 * recomputes the origin from the exit point, so the label settles back in the
 * direction the pointer went. Keyboard focus has no position, so it rolls from
 * the first letter.
 *
 * ONE TRANSITION, RE-TIMED PER CHANGE. Each letter column carries a CSS
 * transition whose delay is rewritten in the SAME render as its transform.

  // ---------------------------------------------------------------
  // Full source available with a viberdy Pro subscription.
  // https://viberdy.dev/pricing
  // ---------------------------------------------------------------
}
Details

About this component

Rolling labels have become a fixture of agency sites, and almost all of them stagger by index, so the roll always begins at the first letter regardless of how the pointer arrived. This one measures which letter is nearest the entry point and delays every other letter by its distance from it, so entering from the right starts the roll on the right and entering in the middle spreads it both ways; leaving recomputes the origin from the exit point, so the label settles back in the direction the pointer went. The mechanism is deliberately plain. Each letter is a clipped inline-block holding the glyph twice, and rolling is a translateY on that column. The delay and the transform are written into the same inline style, and because a CSS transition takes its delay from the after-change style, an interrupted roll simply reverses from where it is — no timers, no animation objects. The letters are aria-hidden and the label lives in a visually hidden span rather than an aria-label, which browser translation would skip. Three variants share the timing: a solid primary, an outline secondary and a bare text link.

Curator’s note

Every rolling-label button staggers by index, so it always starts at the left no matter where you touched it. Making the delay a distance from the entry letter costs one loop.

Pairs well with