Shape Morphing Icons in Button on Click

Avatar of Geoff Graham
Geoff Graham on

The idea here is use an SVG icon in a button and swap that icon out for another when the button is clicked. A button click often suggests an action has been taken, so switching icons can be a nice UI touch to show the change in context and confirm that the action has happened.

A possible use case could be a download button. The icon in the button might initially indicate that the button will trigger a download but change to a checkmark when the button has been clicked.

See the Pen MorphSVG in Button on Click by Geoff Graham (@geoffgraham) on CodePen.

Let’s create a snippet that accomplishes this pattern so we can use it in other similar contexts.


While we’re filing this as an SVG snippet, we’re going to be relying on GSAP’s TweenMax, which is a JavaScript library specifically for animating SVG, and MorphSVG, which is a component of TweenMax.

Yes, SVG does indeed have native support for animations that wold allow us to accomplish the same thing. However, with SMIL support waning in future versions of WebKit and Blink browsers and it’s total lack of support in IE and Edge, GSAP becomes a much more attractive alternative.

Let’s fire those up and build us a pattern!

Step 1: Choose the SVG Shapes

We’re going to swap one shape out for another. The shapes used for this snippet came from IcoMoon, which has tons of free vector icons, but you could make your own as well. Either way, prepare your shapes and let’s add them to the HTML inside of a button element.

<!-- The button element (we could have used `<button>`) -->
<a class="button" href="#">
  <!-- The main SVG where both shapes will be drawn -->
  <svg id="icons" class="button-icons" version="1.1" xmlns="" viewBox="0 0 32 32">
    <!-- The download icon -->
    <path id="download" class="icon" d="M28 16h-5l-7 7-7-7h-5l-4 8v2h32v-2l-4-8zM0 28h32v2h-32v-2zM18 10v-8h-4v8h-7l9 9 9-9h-7z"></path>
    <!-- The checkmark icon -->
    <path id="checkmark" class="icon" d="M27 4l-15 15-7-7-5 5 12 12 20-20z"></path>

  <!-- The button text -->
  <!-- The ID will be used to swap the text with JavaScript -->
  <span id="button-text">Download</span>


Step 2: Style the Button and SVG

We can set up the CSS next. Most of the styles in our example are specific to the demo. Here’s the bare minimum of what’s necessary to make this functionality work.

Note that the key piece is hiding the shape we are morphing into by default. We do this because we need both shapes in the DOM for MorphSVG to swap one for the other, but we cannot show both at the same time. That means we hide the second shape and let MorphSVG work its wonders to make it visible when it needs to.

/* The main SVG */
.button-icons {
  width: 1.25em;

/* The individual icons */
.icon {
  fill: #fff;

/* We hide the checkmark by default */
#checkmark {
  visibility: hidden;

Step 3: Mighty Morphin’ SVGs!

This is where TweenMax and MorphSVG come into play. The full code for the example is provided below, but it follows this general script:

  • Define a few variables to start so we can refer to them throughout the code without having to write them out each time:
    • icons: the full SVG element
    • button: the button (or link) that contains our shapes
    • buttonText: the text inside the button
    • buttonTL: The MorphSVG command to swap the download icon for the checkmark icon
  • Hey, JavaScript, please watch for the button to be clicked and play the MorphSVG animation forward and in reverse on alternate clicks.
  • Oh and, hey JavaScript, also swap the button text when the button is clicked.
  • Thank you, JavaScript
// We're going to select some things and make them variables
var select = function(s) {
  return document.querySelector(s);
  icons = select('#icons'),
  button = select('.button'),
  buttonText = document.getElementById("button-text")

// Morph the Download icon into the Checkmark icon
var buttonTl = new TimelineMax({paused:true});'#download', 1, {

// On button click, play the animation
button.addEventListener('click', function() {
  if (buttonTl.time() > 0) {
  } else {;

// On button click, swap out the button text
button.addEventListener('click', function() {  
  if (button.classList.contains("saved")) {
    buttonText.innerHTML = "Download";
  } else {
    buttonText.innerHTML = "Saved!";
}, false);


The following is a demo of the code we’ve covered:

See the Pen MorphSVG in Button on Click by Geoff Graham (@geoffgraham) on CodePen.