I believe small details can go a long way in improving a project - including this website! You may have noticed the subtle (or not so subtle) signature animation on the navigation bar and the footer.
If you want to build your own animated signature component for your website, here's how.
The Tools 🛠️
- SVGs (Scalable Vector Graphics)
- React (My front-end framework of choice)
- Framer Motion (A React animation library)
1. Vectorize the Signature.
We want the signature in a vector image format so we can animate it as if it was drawn.
Vector 🖋️ graphics use math to render images. Raster 👾 graphics use a set of pixels to render images.
Essentially, vector images are composed of paths rather than pixels. This makes vector images scalable, lightweight, and easy to manipulate. Easy to manipulate means easy to animate.
Let's run through the vectorizing process:
- Draw your signature on paper.
- Scan or take a picture of your signature. Upload this scan onto your machine.
- Use the pen tool in your vector illustration application of choice to trace your signature in one stroke. (this is important, and you'll see why later)
- Export the signature vector as an SVG. (not PNG, JPEG, etc)
What if I don't have a vector illustration app already?
Figma is a free and collaborative design web app that has vector illustration tools, like the pen tool.
Once you create and open a design file in Figma, here are the relevant official tutorials that you'll need:
If you've gotten this far, awesome stuff! 🎉. It's time for the next step.
2. Create the Signature Component
In your React repository, create a new file called Signature.jsx
(or Signature.tsx
for you fellow Typescript fans).
The functional component boilerplate should look like so:
export default function Signature() {
return (
<p>Hello World</p>
)
}
Of course, this simply renders "Hello World" if added to the component tree. We want it to render the SVG that we exported earlier. To do that, we're gonna dive right into the SVG markup. Maybe we'll learn a thing or two. ✨
If you open the SVG of the signature in a text editor, you should see a familiar HTML/XML like markup in this format:
<svg
width="108"
height="89"
viewBox="0 0 108 89"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="..."
style="some styling"
/>
</svg>
All SVG's are wrapped in the svg
element. In this case, we only have one path element inside our SVG. Remember Why?
It's super important that it's only one path element because it reduces the complexity of our animation. Animating one path element is so much easier.
Another note is that the d
attribute on the path
element specifies the bezier curve using curve commands.
Anyway, HTML (and by extension JSX) can render SVGs in two ways:
- Using the
img
element (like any image on the web).<img src="vector.svg" alt="You just got Vectored"/>
- The
svg
element.
Since we want to animate the SVG, the second option is advantageous. Copy and paste the signature's SVG into your component. It should look something like this:
export default function Signature() {
return (
<svg
width="108"
height="89"
viewBox="0 0 108 89"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="..."
style="some styling"
/>
</svg>
)
}
3. Animate the Signature Component
It's time to breathe some life into our signature!
If you haven't already, install framer-motion
using your preferred package manager:
npm i framer-motion
then add an import for the motion
component(s):
import { motion } from "framer-motion"
Motion Components
motion
has a set of components which are DOM primitives, but supercharged with smooth animation capabilities. There's a motion
component for every HTML and SVG element (including the path
element). Each motion
component allows you to:
- Animate via a simple prop.
- Respond to gestures with animations.
- Add drag, pan, hover and tap gestures.
- Deeply animate throughout React trees via variants.
We're gonna be exploring the first two capabilities with the signature.
Animate
Let's swap the svg
and path
elements with their respective motion
components:
export default function Signature() {
return (
<motion.svg
...
>
<motion.path
...
/>
</svg>
)
}
A motion
component can take in variants (or keyframes) of the component as a prop that it will transition to and from. We specify these variants with an object.
The variants that I used look like this:
const variants = {
hidden: {
pathLength: 0,
},
visible: {
pathLength: 1,
}
}
I want the signature to be hidden initially, and gradually become more visible. We specify this with the initial
and animate
props.
<motion.path
d="..."
strokeDasharray="0 1"
variants={variants}
initial="hidden"
animate="visible"
style="some styling"
/>
Finally, we want to specify some transition details for the animation. We can specify this as follows.
<motion.path
...
transition={{ease: "easeInOut", duration: 2, delay: 0.5}}
/>
The transition
prop takes an object that specifies the transition. Read about it here. I'll briefly explain the three values I specified:
ease: "easeInOut"
Specifies the easing function to use in the transition. "easeInOut" is one of Framer's built in functions, but you can also specify a custom cubic bezier curve for the easing function. Custom Easing Functions
duration: 2
Specifies the duration of the animation. (2 seconds)
delay: 0.5
Specifies the delay starting from componentDidMount()
to the start of the animation. (0.5 seconds)
Respond to Gestures with Animations
You might not have noticed, but you can hover over the signature, and the signature gets erased, and then redrawn when not hovering. This is super simple with framer-motion
:
<motion.path
...
whileHover="hidden"
...
/>
This sets the whileHover
animation state to be "hidden", and the same transition is applied. Framer Motion is animation magic 🪄.
We did it! 🎊
Now you can draw a signature with the help of React and Framer Motion! Hopefully you're inspired to create some cool, more complex animations with Framer Motion in your React projects.