Buttons that Spark Joy

Written by Alex Trost

Buttons are such a foundational part of any website that we often take them for granted. They’re an iconic component in web design, but it’s rare that a button delights the user or creates a memorable experience. They’re a workhorse; they execute some function.

What if we could make certain actions not just successful, but celebrations? That’s what Aaron Iker’s buttons bring to the web. Today we’re demystifying some fantastically fun buttons he’s made with different GSAP techniques.

In particular, we’ll be learning about GSAP’s powerful plugins. We’ll see how Aaron uses the Draggable, MorphSVG, and Physics2D plugins to make some delightful interactions. Most of these plugins are part of GreenSock’s paid license, but you can use them on CodePen without charge!

It’s a GSAP-packed article with plenty of techniques to make your UI win top prize. Let’s ride!

Confirm Confetti Button

This button simulates confetti being shot into the air and falling with the Physics2D plugin.

Let’s break down how Aaron created this mini celebration.

The first thing to note: He imported GSAP and the Physics 2D Plugin through the CodePen settings. Then he registers the plugin at the top of his JavaScript. Anytime you use a GreenSock plugin, you need to register it like this.

gsap.registerPlugin(Physics2DPlugin)

He’s created a particles() function, which takes a few arguments and generates all the confetti.

function particles(parent, quantity, x, y, minAngle, maxAngle) {
...
}

parent is a reference to a DOM element, in this case button.querySelector('.emitter'), which is a 1px div positioned right at the mouth of the cone

quantity is the total number of particles, Aaron’s using 100

x and y are the coordinates where the confetti will shoot from, relative to parent

minAngle and maxAngle set the bounds for a random number that determines the initial angle the particle is shot towards.

Randomizing Values

The rest of the values are randomized and simulated with the Physics2D plugin. With 100 particles, each confetti blast might feel the same, but you can see the difference if we only fire off one particle.

Click the button a bunch of times and notice that he’s randomizing the following for each confetti piece:

  • The color of each piece
  • The initial angle that the confetti travels in
  • The velocity
  • The rotation of the confetti piece on its own axis
  • The scale of the confetti

While there’s a lot of randomization, it’s all happening with set boundaries and 100 elements, so Aaron can be sure the user will see the approximate effect he wants.

If you want to spot the bits of randomization, check for where he uses GSAP’s built-in random utility function:

gsap.utils.random(min, max)

Physics2D Plugin

The Physics2D plugin gives you a simple physics engine to easily add some realism to your animations. You can set the object’s velocity, angle, gravity, acceleration, accelerationAngle, and/or friction.

For this, Aaron is only setting the angle, velocity, and gravity, and the plugin takes care of the rest. Here’s a version with a GUI handling the different variables. Mess with the gravity, number of particles, and have fun with it!

Bookmark Button

Next up is this Bookmark Button demo based on a Dribbble shot by Yup Nguyen. Give it a click and watch the icon.

I want to focus on the flip, where the ribbon unfurls with a satisfying drop. Hit the buttons above a few times to get a good sense of the effect.

Here’s an isolated and slowed down version only showing the transition from unselected to selected to break down the technique.

The magic is happening with the .corner path, so I’ve made it blue and dropped the opacity on the rest to understand it better. Click the ribbon to trigger the animation.

Aaron can achieve this with only five paths for that shape, letting MorphSVG handle the rest.

6 keyframes of the different SVGs that Aaron is morphing between. Starts with a line and eventually falls to two triangles at the bottom.

Play the slowed-down version again, and you’ll pick out each of these steps in the animation.

MorphSVG Plugin

As we touched on in our first issue, you can easily morph between different SVG paths so long as they have the same number of points. The browser will shift the points for you, no sweat.

For this, you can think of points like vertices on shapes. You can transition one triangle into another triangle easily with just CSS.

But what about when the number of points isn’t equal? If you’re going to turn a triangle into a square with CSS alone, you’re gonna need another point.

Doing this by hand for complex shapes can be tedious. That’s where the MorphSVG plugin comes in. It does the heavy lifting so you can smoothly transition between any SVG Shapes. It adds points where needed and handles the transition between each state.

Here I took three Feather Icons off the shelf and made this with just a couple lines of code.

Check out the MorphSVG Plugin docs to learn more.

Drag to Confirm Button

Aaron brings the “swipe to confirm” UI pattern from mobile to the web with the Draggable plugin.

The Draggable plugin not only makes DOM elements draggable but gives you a ton of extra features.

Here’s the code where Aaron sets up his Draggable instance.

Draggable.create(handle, {
        type: 'x',
        bounds: button,
        onDrag(e) {
          ...
        },
        onRelease(e) {
          ...
        }
})

The type allows you to choose the drag position, rotation, or scroll for the element. 'x' locks its motion to the horizontal x axis.

button references the button DOM element, which is why we can’t drag the handle beyond the blue button’s edges.

onDrag() and onRelease() are callback functions on Draggable. onDrag() is called over and over as you drag the handle, and onRelease() is only called once you’ve let go.

In the onDrag() function, Aaron checks the x position of the handle and uses that to scrub through an animation for the handle and drop-zone. Let’s check out a larger version with some info at the top.

The animation is more apparent here, and we can now see the dragging status. We also have this progress value, and that’s what determines the animation’s progress.

As we drag, the value stays 0 until we bring the handle close enough to the drop zone. Then it climbs towards 1 and falls back down to 0 past a certain point. Notice how the shapes only start to animate when the value is greater than 0.

Once you let go, the onRelease() callback fires, and that’s where Aaron uses Draggable.hitTest() to determine if the handle is on the drop-zone. If it is, we transition to the “Done” state. If not, the handle snaps back to start.

Awesome technique!

Aaron’s Process - Q&A

Aaron’s CodePen portfolio is so consistent and high-quality that I wanted to learn more about his process.

I’ve always known you as the developer who makes amazing buttons and other UI elements. What do you love about this kind of work?

Aaron: I always loved to amaze and entertain people by showing them what’s possible with some playful concepts. Another motivation is to rethink existing elements and bring some fun to the World Wide Web. I also like to find great concepts on Dribbble and bring them to life and make them usable. It’s also a way to challenge myself.

A concept illustration of a mobile tab bar that pops icons up as if they were in liquid.

A concept sketch for Aaron’s Tabbar

One thing that stands out with your work is how perfect the easing and timing functions feel when clicked or toggled. How did you develop this skill?

Aaron: Recreating stuff from more experienced people was really helpful at the beginning. Over time you get a better feeling for natural and smooth timing. It’s always important to collect feedback from others (Dribbble, CodePen, Twitter, DM) - they will mention stuff you won’t see yourself if you are working on a specific concept for a long time.

Your animations are much smaller than most other CodePens and demos, so it seems like each pixel needs to be perfect. Is there a difference between creating a full-screen animation, and creating a 160px by 50px button animation?

Aaron: The reason for the small scale is I want to make my Pens usable, so I am using common button sizes. I don’t think there is a massive difference because both should be pixel-perfect 😄.

Sometimes it may be harder to create an animation with limited pixels. During development I scale it up to not miss something and be as accurate as possible (you may need a little bit perfectionism for that 😄).

A picture of a button with a "Launch Site", Rocket blastoff, and "Site Live" state

The three stages of Rocket Launch Button

Do you have any favorite resources you’d recommend for learning general animation skills or UI engineering?

Aaron: I always tell people they should just start - learning by doing is the key. It’s incredible how fast you’ll see your first results. If you lack ideas, go to Dribbble and browse through the animations there. Just make sure to give credit if you recreate something. I also love to work with GSAP for more complex animations. It’s well documented & easy to learn, so you should explore it if you haven’t heard of it.

Special thanks to Aaron Iker for giving us insight into his fantastic work! Go follow him on Twitter and check him out on Dribbble.

Subscribe to get future issues in your inbox!