dev

Ripple is a script that adds a ripple effect to most buttons and allows users to add ripples to any element too. Original code from Polymer Project's paper-ripple component.

Installation

About

As described by Material Design, ripples are a visual form of feedback for touch events providing users a clear signal that an element is being touched.

There are three types of ripple motions:

Ripple's duration, color, duration, decay duration, and size are some of the characteristics you can customize to fit your needs and brand/stylistic choices.

Usage

You don't have to do anything besides importing the script to make it work. But you can configurate the script to add more elements to be able to have the ripple effect and you can also change how the ripple itself behaves on certain elements.

Adding elements

You can allow more elements to have the ripple effect by just creating an object named window.ripplesConfig with any combination of the following properties: normalRipples, recenteredRipples, and/or unboundedRipples. The value of any of these properties should be a NodeList (a list of elements given by the document.querySelectorAll() method).

Each property grants ripples to the matching elements, but their behavior will depend on which category they are set to (see the about section to learn how each category behaves).

TL;DR: An example of a configuration script that uses all three ripple categories looks like this:

window.ripplesConfig = {
  'normalRipples': document.querySelectorAll('.elements-1, .elements-2'),
  'recenteredRipples': document.querySelectorAll('.foo .bar'),
  'unboundedRipples': document.querySelectorAll('.lorem .ipsum')
};

This basically means that:

Another way is to add any of the following data-attributes to any element to give it a ripple effect on touch without editing any JavaScript:

An example of each case would be:

Code Result
<div class="wds-button has-ripple">Touch me!</div>
Touch me!
<div class="wds-button recentered-ripple">I am re-centered!</div>
I am re-centered!
<div class="wds-button unbounded-ripple">And I am unbounded!</div>
And I am unbounded!

Another thing you can do is to add a subtle effect when the user is hovering over a ripple surface which may not look like it can trigger such effect. This can be done by using pseudo-classes such as ::before or ::after on a relative-positioned element:

Code Result

<div class="card has-ripple">Hover and touch me!</div>

.card {
  align-items: center;
  background-color: var(--theme-page-background-color--secondary);
  border-radius: 8px;
  display: flex;
  height: 14em;
  justify-content: center;
  margin: 1em;
  overflow: hidden;
  padding: 24px;
  position: relative;
  text-align: center;
  width: 10em;
}

.card:hover {
  cursor: pointer;
}

.card::before {
  background-color: currentColor;
  content: '';
  height: 100%;
  left: 0;
  opacity: 0;
  pointer-events: none;
  position: absolute;
  top: 0;
  transition: opacity 15ms linear, background-color 15ms linear;
  width: 100%;
  z-index: 1;
}

.card:hover::before {
  opacity: .04;
}

.card:active::before,
.card:focus-within::before {
  opacity: .12;
  transition-duration: 75ms;
}

Hover and touch me!

Modifying behavior

You can change some properties of the ripples on a per-element basis or to groups of elements by using CSS custom properties (variables). To learn what each variable does, go to the API section.

TL;DR: An example of a configuration stylesheet that uses all available variables looks like this:

.nice-button {
  --ripple-config__duration--ms: 1000;
  --ripple-config__end-duration--ms: 500;
  --ripple-config__max-radius--px: 200;
  --ripple-config__min-duration--ms: 600;
  --ripple-config__timing-function: ease;
}

Which means that:

Additionally, you can change some visual aspects of it as well:

.nice-button {
  --ripple-color: lime;
  --ripple-border-radius: 0;
  --ripple-opacity: 0.5;
}

Which also means that:

Examples

Button Secondary Text Active Full-width


Example

A new morning Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque in nisl sed quam convallis laoreet a mollis arcu. Sed molestie consequat libero vitae dictum.

Secondary Primary

Example

A new morning Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque in nisl sed quam convallis laoreet a mollis arcu. Sed molestie consequat libero vitae dictum.

Secondary Primary


Unbounded ripple. This card's CSS:
#var-card-1 {
  --ripple-config__duration--ms: 6000;
  --ripple-config__max-radius--px: 300;
  --ripple-color: #3ea6ff;
}
Recentered ripple. This card's CSS:
#var-card-2 {
  --ripple-config__duration--ms: 600;
  --ripple-config__max-radius--px: 150;
  --ripple-config__min-duration--ms: 500;
  --ripple-color: #e91e63;
  --ripple-border-radius: 30%;
  --ripple-opacity: 40%;
}
Normal ripple. This card's CSS:
#var-card-3 {
  --ripple-config__end-duration--ms: 6000;
  --ripple-config__max-radius--px: 1000;
  --ripple-config__timing-function: ease;
  --ripple-color: #64dd17;
  --ripple-border-radius: 0;
  --ripple-opacity: 0.3;
}
Normal ripple. This card's CSS:
#var-card-4 {
  --ripple-config__duration--ms: 1500;
  --ripple-config__end-duration--ms: 1600;
  --ripple-config__max-radius--px: 50;
  --ripple-config__min-duration--ms: 1000;
  --ripple-config__timing-function: ease-out;
  --ripple-color: #d500f9;
  --ripple-border-radius: 50%;
  --ripple-opacity: .35;
}
Material Design Ripple
Code Result

<div class="mdc-ripple has-ripple" id="mdc-card-1">Normal speed</div>
<div class="mdc-ripple has-ripple" id="mdc-card-2">1000% Slower</div>

/* (Cards' CSS not included). */
.mdc-ripple::before {
  background-color: currentColor;
  content: '';
  height: 200%;
  left: -50%;
  opacity: 0;
  pointer-events: none;
  position: absolute;
  top: -50%;
  transition: opacity 75ms linear;
  width: 200%;
  z-index: 1;
}

.mdc-ripple:hover::before {
  opacity: .04;
}

.mdc-ripple:is(:focus, :focus-within, :active)::before {
  opacity: .12;
}

/* Normal speed. */
.mdc-ripple {
  --ripple-config__duration--ms: 225;
  --ripple-config__end-delay--ms: 3000;
  --ripple-config__end-duration--ms: 150;
  --ripple-config__max-radius--px: 2000;
  --ripple-config__min-duration--ms: 75;
  --ripple-config__timing-function: cubic-bezier(.4, 0, .2, 1);
  --ripple-opacity: .12;
}

/* x10 (1000%) slower. */
#mdc-card-2.mdc-ripple {
  --ripple-config__duration--ms: 2250;
  --ripple-config__end-duration--ms: 1500;
  --ripple-config__min-duration--ms: 750;
}

Normal speed
1000% Slower

API

HTML elements

Note that you don't have to write any HTML in order to make this script work, but you may want to know the purpose of each generated element.

HTML element Description
<div class="ripple-container"></div>
Mandatory. Wraps and limits ripple's location.
<div class="ripple"></div>
Mandatory. It's the ripple itself.

CSS selectors

CSS selector Description
[ripple]
[data-ripple]
Selects any element with the ripple attribute. These elements will have a ripple upon script execution.
[recentered]
[data-recentered]
Selects any element with the recentered attribute. These elements will have a recentered ripple upon script execution.
[unbounded]
[data-unbounded]
Selects any element with the unbounded attribute. These elements will have a unbounded ripple upon script execution.

CSS variables

CSS variable Description
--ripple-config__duration--ms Duration (in miliseconds) of the ripple expansion animation. Defaults to, at least, 800ms.
--ripple-config__end-duration--ms Duration (in miliseconds) of the ripple fade-out animation. Defaults to 150ms (on touch) or 400ms (on key press).
--ripple-config__max-radius--px Maximum radius of the ripple (in pixels). Defaults to 300px.
--ripple-config__min-duration--ms Minimum duration (in miliseconds) of the riple expansion animation. Defaults to 800ms.
--ripple-config__timing-function CSS easing function that determines the expansion animation's speed rate. Defaults to cubic-bezier(.2, .9, .1, .9).
--ripple-color Determines the ripple's color. Defaults to currentText (the element's current text color).
--ripple-border-radius Determines the ripple's border-radius. Defaults to 50% (full circle).
--ripple-opacity Determines the ripple's opacity. Defaults to 25%.
--ripple-checked-color Determines the ripple's color on checked elements such as checkboxes, radio buttons, and toggles. Defaults to var(--theme-link-color).
--ripple-unchecked-color Determines the ripple's color on un-checked elements such as checkboxes, radio buttons, and toggles. Defaults to var(--theme-body-text-color).
--ripple-checked-opacity Determines the ripple's opacity on checked elements such as checkboxes, radio buttons, and toggles. Defaults to 20%.
--ripple-unchecked-opacity Determines the ripple's opacity on un-checked elements such as checkboxes, radio buttons, and toggles. Defaults to 15%.
Text above can be found here (edit)