Skip to content

Instantly share code, notes, and snippets.

@savaryna
Last active February 9, 2022 20:16
Show Gist options
  • Save savaryna/7ee9d7a4531e6c717f5af9599ea2a799 to your computer and use it in GitHub Desktop.
Save savaryna/7ee9d7a4531e6c717f5af9599ea2a799 to your computer and use it in GitHub Desktop.
A simple Material Design ripple effect in React
// Demo: https://jsfiddle.net/ogb6cq7s/96/
// An example App
function App() {
return (
<React.Fragment>
<p>Some buttons</p>
<Button>Button #1</Button>
<Button>Button #3</Button>
<Button>Button #4</Button>
</React.Fragment>
);
}
// An example Button component
function Button({ children }) {
const [rippleProps, setRippleProps] = React.useState({});
function updateRipple({ clientX, clientY, currentTarget }) {
setRippleProps({
clientX,
clientY,
currentTarget,
className: "ripple",
});
}
return (
<button onMouseDown={updateRipple}>
<Ripple {...rippleProps} />
{children}
</button>
);
}
// The Ripple component
// function Ripple({ clientX: 0, clientY: 0, currentTarget: null, className }) {
function Ripple({ clientX, clientY, currentTarget, className }) {
// Could useState if you want to remove ripple onAnimationEnd
let style = {
top: 0,
left: 0,
};
if (currentTarget) {
const { top, left } = currentTarget.getBoundingClientRect();
style.top = clientY - top;
style.left = clientX - left;
}
return (
<span
// Force re-render to restart CSS animation
key={Math.random()}
style={style}
className={className}
ariaHidden={true}
/>
);
}
ReactDOM.render(<App />, document.querySelector("#app"));
#app {
display: flex;
flex-direction: column;
align-items: start;
gap: 8px;
padding: 40px;
}
button {
position: relative;
padding: 8px 16px;
border: none;
border-radius: 5px;
overflow: hidden;
cursor: pointer;
user-select: none;
}
button + button {
color: blue;
}
button + button + button {
color: red;
}
.ripple {
position: absolute;
width: 100%;
padding-top: 100%;
border-radius: 50%;
background-color: currentColor;
opacity: 0.1;
transform: translateX(-50%) translateY(-50%) scale(0);
will-change: transform, opacity;
animation: rippleAnimation 1s;
}
@keyframes rippleAnimation {
to {
transform: translateX(-50%) translateY(-50%) scale(5);
opacity: 0;
}
}
@savaryna
Copy link
Author

savaryna commented Feb 9, 2022

Demo available on jsFiddle.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment