# use-ripple-hook

> Customizable, lightweight React hook for implementing Google's Material UI style ripple effect

Latest version **2.0.0** (published 2026-04-27) · ISC license · 0 weekly downloads

## Install

```sh
npm install use-ripple-hook
pnpm add use-ripple-hook
yarn add use-ripple-hook
bun add use-ripple-hook
```

## Health

**Score 55/100 (C)** — status: active.

Positive: has types; esm support; no vulnerabilities.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 2.0.0 |
| Published | 2026-04-27 |
| First published | 2022-02-12 |
| Weekly downloads | 0 |
| License | ISC |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Node | >=18 |
| Dependencies | 0 |
| Unpacked size | 24.4 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | Jonathan Asplund |
| Maintainers | asplunds |
| Keywords | useripple, use-ripple, material, ripple, react, hook |

## Links

- npm: https://www.npmjs.com/package/use-ripple-hook
- Repository: https://github.com/asplunds/use-ripple
- Homepage: https://github.com/asplunds/use-ripple#readme
- Issues: https://github.com/asplunds/use-ripple/issues
- npm.io page: https://npm.io/package/use-ripple-hook

## Alternatives

- [mobx-react](https://npm.io/package/mobx-react.md) — 2.8M weekly downloads
- [rc-tree](https://npm.io/package/rc-tree.md) — 2.6M weekly downloads
- [@react-oauth/google](https://npm.io/package/@react-oauth/google.md) — 1.3M weekly downloads
- [@wagmi/connectors](https://npm.io/package/@wagmi/connectors.md) — 877.0K weekly downloads
- [vee-validate](https://npm.io/package/vee-validate.md) — 836.4K weekly downloads

## Recent versions

- 2.0.0 (latest) — 2026-04-27
- 1.1.25 — 2026-04-27
- 1.1.0 — 2026-04-27
- 1.0.24 — 2023-10-06
- 1.0.23 — 2023-10-06
- 1.0.22 — 2022-06-18
- 1.0.21 — 2022-06-15
- 1.0.20 — 2022-02-25
- 1.0.19 — 2022-02-19
- 1.0.18 — 2022-02-19
- 1.0.17 — 2022-02-19
- 1.0.16 — 2022-02-19
- 1.0.15 — 2022-02-12
- 1.0.14 — 2022-02-12
- 1.0.13 — 2022-02-12
- … 12 more at https://npm.io/package/use-ripple-hook/versions

## README

# useRipple - Material UI ripple effect

Fully customizable, lightweight React hook for implementing Google's Material UI style ripple effect

![useRipple showcase GIF](https://i.imgur.com/8yu6uaR.gif "useRipple showcase")

[![Edit great-nash-zhyfm](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/great-nash-zhyfm?fontsize=14&hidenavigation=1&theme=dark)

## Installation

```
npm install use-ripple-hook
```

## Usage

```tsx
import React from "react";
import { useRipple } from "use-ripple-hook";

function Button() {
  const [ripple, event] = useRipple();

  return (
    <button ref={ripple} onPointerDown={event}>
      Default Ripple
    </button>
  );
}
```

## Options

### Default options

```ts
useRipple({
  duration: 450,
  color: "rgba(255, 255, 255, .3)",
  cancelAutomatically: false,
  className: "__useRipple--ripple",
  containerClassName: "__useRipple--ripple-container",
  ignoreNonLeftClick: true,
  timingFunction: "cubic-bezier(.42,.36,.28,.88)",
  disabled: false,
  ref: internalRef,
  onSpawn: undefined,
});
```

### Options reference

| Property              | Description                                                                                      | Type                               | Default                         | Optional |
| --------------------- | ------------------------------------------------------------------------------------------------ | ---------------------------------- | ------------------------------- | -------- |
| `duration`            | Duration in milliseconds                                                                         | `number`                           | `450`                           | ✔️       |
| `color`               | Color of the ripple effect                                                                       | `string`                           | `rgba(255, 255, 255, .3)`       | ✔️       |
| `cancelAutomatically` | If `true`, the ripple will begin to cancel after 40% of the duration                             | `boolean`                          | `false`                         | ✔️       |
| `className`           | The ripple element's class name                                                                  | `string`                           | `__useRipple--ripple`           | ✔️       |
| `containerClassName`  | The container element for the ripples                                                            | `string`                           | `__useRipple--ripple-container` | ✔️       |
| `ignoreNonLeftClick`  | If `false`, non left click events such as right click and middle click will also trigger ripples | `boolean`                          | `true`                          | ✔️       |
| `timingFunction`      | Transition timing function of the transform animation                                            | `string`                           | `cubic-bezier(.42,.36,.28,.88)` | ✔️       |
| `disabled`            | If `true`, no ripples will be spawned                                                            | `boolean`                          | `false`                         | ✔️       |
| `ref`                 | Optional outside ref, if unset, internal ref will be used                                        | `React.RefObject<T>`               | `undefined`                     | ✔️       |
| `onSpawn`             | A callback which is triggered when a ripple is spawned                                           | [options.onspawn](#optionsonspawn) | `undefined`                     | ✔️       |

### `options.onSpawn`

**Type**

```ts
type OnSpawnCB = (ctx: {
  /** the ripple element */
  readonly ripple: HTMLDivElement;

  /** cancels the current ripple animation */
  readonly cancelRipple: () => void;

  /** the ref to the ripple host element */
  readonly ref: React.RefObject<T>;

  /** the event that triggered the ripple (ts: casting required) */
  readonly event: unknown;

  /** the ripple container element */
  readonly container: HTMLDivElement;
}) => void;
```

**Example**

```js
useRipple({
  /* ... */
  onSpawn: ({ ripple, ref, event, container }) => {
    console.table({ ripple, ref, event, container });
  },
});
```

## Perfect circle

As demonstrated in the below GIF, useRipple adjusts the circle size to always for the host element's border box.

![useRipple showcase GIF](https://i.imgur.com/OU9YJAh.gif "image Title")

## Higher order function (HOF)

If you want to memoize a configuration for your ripple you can use the built in `customRipple()` function.

You can override the options you memoized for your custom ripple hook. The two options will be merged.

### Usage

```tsx
import { customRipple } from "use-ripple-hook";

const useMyRipple = customRipple({
  color: "rgb(144, 238, 144, .7)",
  duration: 700,
});

function Button() {
  const [ripple, event] = useMyRipple({}); // Optionally override previous config

  return (
    <button ref={ripple} onPointerDown={event}>
      Memoized Ripple
    </button>
  );
}
```

This is useful if you want to avoid repetition in your code or if you want multiple different ripple effects for different components.

## Examples

A live CodeSandbox is available <a target="_blank" href="https://codesandbox.io/s/great-nash-zhyfm?file=/src/App.tsx">here</a>.

This repo also ships two runnable example apps under [`examples/`](./examples) that consume the package via the pnpm workspace:

- [`examples/vite-example`](./examples/vite-example) — Vite 8 + React 19.
- [`examples/nextjs-example`](./examples/nextjs-example) — Next.js 15 (App Router). The hook lives in a `"use client"` component because it touches the DOM.

See [`examples/README.md`](./examples/README.md) for setup instructions.

## Contributing

Contributions of any form are appreciated, opening issues on the Github repository as well as creating pull requests are both welcomed for anyone to do.

---
_Source: https://npm.io/package/use-ripple-hook · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
