Utilities✨ Premium

Border Ripple

A button where every click, by finger or keyboard, sends out three expanding border ripples and a light that travels around the frame.

JSClickRipple

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Utilities has 43 effects, including 3 free. Explore the category →

3 usage examples

"Confirm order" button on a restaurant kiosk — Border Ripple example 1

① "Confirm order" button on a restaurant kiosk

WhenOn the Grillorn kiosk, the summary (smoked brisket bun, rosemary fries, lemonade, €19) fills the left side; on the right, a big orange "Confirm order" button. On touch, ripples spread from the button and the line below reads "Sent to the kitchen · no. 482".
WhyOn a touch screen with no vibration or sound, the ripples confirm the finger was registered; at the size of a big button they can be seen from a distance.
Settings196 × 170 px brr-box, 18 px corners, 3 px border; --brr-color: #fb923c, --brr-light: #fed7aa, orange --brr-rest and --brr-hover. The capture clicks the real button (click()) every 1.8 s; the message comes from the scene script.
Ticking tasks on a building site list — Border Ripple example 2

② Ticking tasks on a building site list

WhenOn today's list for the Tervaneuil site, each task (formwork, window frames, electrical conduits…) is a clickable row with the first name of the person in charge. Clicking a row ticks or unticks it, and a blue ripple runs around the row.
WhyAt this small scale the ripple is a quiet receipt: you see which row just changed, even if your eyes were on another part of the screen.
Settingsbrr-box on full-width 46 px rows (one root per task), 1 px grey border, --brr-color: #2563eb, --brr-light: #93c5fd. Clicks come from the capture's mouse; the tick box is handled by the scene.
Pads in a rhythm game — Border Ripple example 3

③ Pads in a rhythm game

WhenIn Tambrello, four pads D, F, J and K wait for the falling notes. Every hit, by keyboard or finger, bursts ripples in the pad's colour and adds 50 points to the score.
WhyFeedback has to be instant and readable at the music's pace: the ripple starts the moment of the click, and each pad colour keeps its own ripples.
SettingsFour 84 px tall brr-box, each with its own colours (--brr-color pink, blue, green, amber). The D F J K keys call click() on the right pad; a demo game hits one every 420 ms.

How it works

The effect is a real <button type="button"> with the brr-box class: a pale violet 2 px border that gets a little stronger on hover. It holds three <span class="brr-pulse"> (2 px frames, invisible at rest) and a <span class="brr-travel"> carrying the light, then your text.

On every click (mouse, finger, Enter or Space), the script restarts the three frames 200 ms apart: each one starts against the button, moves out to 20 px while rounding its corners and fades in 1 s. At the same time the brr-clicking class starts the light: a 40 px #a78bfa gradient glow running along the top, right, bottom then left in 1.2 s, clipped to the button's edge. Clicking again before the end cancels the pending timers and restarts everything from the beginning.

The script looks for each .fx-0773-root and the button inside it: each copy has its own ripples and timers, and pasting the script twice does not add a second listener. The animations are called brr-pulse and brr-travel, names no other effect in the library uses.

Accessibility

  • Real button: it gets focus with Tab, fires with Enter or Space and is announced as "button" followed by its text. On :focus-visible, a 2 px outline shows 4 px from the edge. (The original version was a <div> that the keyboard could not reach.)
  • Silent decoration: ripples and light are empty <span> with aria-hidden="true"; the button's name is just its text.
  • Reduced motion: under prefers-reduced-motion: reduce, no ripple and no travelling light; the click lights the outline (light border, 4 px ring and glow) for 1.2 s, with no transition, then everything returns to rest.
  • Visual feedback only: the ripple tells screen readers nothing. If the click has a result (order sent, task ticked), announce it in text, for instance in an aria-live="polite" region.

Browser compatibility

CSS (animation of the inset property: Chrome 87, Firefox 66, Safari 14.1; :focus-visible: Chrome 86, Firefox 85, Safari 15.4) and 1.2 KB of JavaScript. Measured in Chromium 151, Firefox 153 and WebKit 26.5 (Playwright): two copies with only the second one clicked, Tab then Enter, finger press, 390 px without overflow, reduced motion with no animation after the click, 0 errors.

Chrome 87+✓ Full (measured)
Firefox 85+✓ Full (measured)
Safari 15.4+✓ Full (measured in WebKit)
Edge 87+✓ Full (Chromium engine)
Mobile iOS 15.4+✓ WebKit engine, not checked on a device
Android Chrome 87+✓ Full (Chromium engine)

Safari 14.1 to 15.3: everything works, with the browser's focus ring instead of the violet outline. Without JavaScript the button stays a button, with no ripple.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0773-root">
  <button type="button" class="brr-box">
    <span class="brr-pulse" aria-hidden="true"></span>
    <span class="brr-pulse" aria-hidden="true"></span>
    <span class="brr-pulse" aria-hidden="true"></span>
    <span class="brr-travel" aria-hidden="true"></span>
    …
  </button>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Ripple colour (CSS — --brr-color) #6366f1 Colour of the three expanding frames.
Light colour (CSS — --brr-light) #a78bfa Travelling glow, focus outline and reduced-motion glow.
Border at rest and on hover (CSS — --brr-rest, --brr-hover) rgba(99, 102, 241, .3) and .5 Colour of the 2 px border; --brr-hover is also the ring under reduced motion.
Ripple reach (CSS — inset: -20px in @keyframes brr-pulse) 20 px How far each ripple goes. Leave at least that much free space around the button.
Delay and count (JS — i * 200, HTML — .brr-pulse) 3 ripples, 200 ms apart Add or remove <span class="brr-pulse">; the script picks them all up.
Size (CSS — width / min-height of .brr-box) at least 200 × 120 px The light follows the edge at any size, from a list row to a full-screen button.

FAQ

Yes: add the brr-box class to your <button>, the four <span> as first children, and wrap it in a .fx-0773-root, one root per button: the script only wires the first button of each root. Keep it for actions that stay on the page: on a link that changes page, the ripple would not have time to be seen.
They go 20 px beyond the button. If a parent has overflow: hidden or the button touches the edge of its container, the part that sticks out is clipped. Leave a 20 px margin, or reduce the reach in @keyframes brr-pulse.
Each click cancels the previous click's timers and restarts the three ripples and the light from the start. There are never duplicate ripples or a forgotten class, even after a burst of clicks.