Shape Morphing Icons in Button on Click

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.

Requirements

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="http://www.w3.org/2000/svg" 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>
  </svg>

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

</a>

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});
buttonTl.to('#download', 1, {
  morphSVG:{shape:'#checkmark'},
  ease:Elastic.easeInOut
})

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

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

Demo

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.

References

Comments

  1. User Avatar
    Wilbert

    I’m using a version of your SVG spirte. Is there a way to make morphing work with the sprite ()?

  2. User Avatar
    Don Allen

    Doesn’t MorphSVG require a GreenSock license?

  3. User Avatar
    preeeby

    Yea really cool, but you have to pay to get GSAP licence to use advanced features like MorphSVG plugin.

  4. User Avatar
    ainalem

    You can do SVG morphing with anime.js: http://anime-js.com/.

    Pen here: https://codepen.io/ainalem/full/wdQzBB/

Submit a Comment

Posting Code

You may write comments in Markdown. This makes code easy to post, as you can write inline code like `<div>this</div>` or multiline blocks of code in triple backtick fences (```) with double new lines before and after.

Code of Conduct

Absolutely anyone is welcome to submit a comment here. But not all comments will be posted. Think of it like writing a letter to the editor. All submitted comments will be read, but not all published. Published comments will be on-topic, helpful, and further the discussion or debate.

Want to tell us something privately?

Feel free to use our contact form. That's a great place to let us know about typos or anything off-topic.

icon-anchoricon-closeicon-emailicon-linkicon-logo-staricon-menuicon-nav-guideicon-searchicon-staricon-tag