Interactive Text Animation with React Hooks

How to animate headings that respond to mouse movements using React Hooks, CSS Modules, CSS variables and clip-path.

I was intrigued after watching Peter Tichy’s video tutorial in which he recreates the interactive animation of this website.

VIdeo Tutorial by ihatetomatoes

I decided to build the same but with the hot new tech like React Hooks, CSS custom properties, clip-path and CSS Modules. Building these small but complete UI pieces really helps in getting a good grasp of the tools without worrying about completing and maintaining large side-projects that will never see the light of the day.

Use Create React App v2.0 and React v16.8.0 or above for this tutorial.

What we’ll be building

I love Messi

When mouse is hovered over Lionel Messi, some part of the text shines with yellow color.

Although not used here, it’s recommended to manage your React components with Bit, to make them organized and reusable for you and your team. It will save a lot of time and work in your next app. Give it a try.

Let’s start hacking

Our React application will have a src/ directory where we will make all the code changes. The file structure will look like this.

$ tree src/ |__ index.js

|

|__ styles.css

|

|__ AnimatedText.js

|

|__ AnimatedText.module.css

The index.js file is the entry point to our application.

index.js

We have imported styles.css file and AnimatedText component. The styles.css file only contains a handful of style declarations mainly to reset the browser styles and center align everything on the page.

styles.css

The AnimatedText component uses three main props — textColor, overlayColor and children.

AnimatedText.js

We import AnimatedText.module.css CSS Module and assign the corresponding classes to the elements. There are two headings, the second one will be styled to overlap the first one.

AnimatedText.module.css

With CSS Modules we can reuse all the declarations of one class in another with the help of composes keyword. That way we can ensure that both the headings have the same base styling. Then we add some more declarations in the second heading to make it an overlay.

We can see that the first heading (red colored) is entirely hidden because the second heading (golden colored) completely overlaps it. Now, we’ll use clip-path to clip the second heading along a certain shape.

Clipping the overlay heading

The clip-path property is used to clip text to a specific shape.

AnimatedText.module.css (updated)

The value of clip-path property is copied from the website linked in the beginning. What it does is difficult to understand by just looking at code. So let’s check the result for certain values of maskX and maskY.

maskX = 50, maskY = 0

maskX = 50, maskY = 50

maskX = 80, maskY = 0

maskX = 80, maskY = -100

Listening to Mouse movements

We add onMouseMove and onMouseOut props to the the animated text container. The mouse move handler uses the state setter provided by the useState React Hook to set the mousePos to the new mouse position. React then assigns the mousePos state to the maskX and maskY CSS variables.

When the mouse leaves the container, handleMouseOut function resets the state to initialMousePos.

The only thing left is to calculate the value of newX and newY. For that we will find the width of the animated text container and use it to find a percentage for newX and newY. The complete implementation of AnimatedText component will look like this.

AnimatedText.js (Ignore the filename of GitHub Gist)

Conclusion

With that, we are done with the implementation of the Interactive Text Animation. The code is available in this codesandbox. Here are some useful hooks with Bit.

If you like my work, don’t be shy about clapping. Follow me on Twitter and Medium or subscribe to my newsletter to get updates on my latest content. Thanks for reading 🙏 Please feel free to comment and ask anything…