Morphing Play/Pause (GSAP MorphSVG)

On each click, GSAP MorphSVGPlugin morphs a single SVG path between a play triangle and a pause shape using rotational type and complexity mapping. A boolean tracks the current state to choose the correct target path on each toggle.

gsapmorphsvgsvgbuttontoggleanimation

Setup — External Scripts

Setup: External Scripts
html
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/MorphSVGPlugin.min.js"></script>

Code

index.html
html
<button data-play-pause="toggle" class="play-pause-button">
  <svg xmlns="http://www.w3.org/2000/svg" width="100%" viewbox="0 0 24 25" fill="none" class="play-pause-icon">
    <path d="M3.5 5L3.50049 3.9468C3.50049 3.177 4.33382 2.69588 5.00049 3.08078L20.0005 11.741C20.6672 12.1259 20.6672 13.0882 20.0005 13.4731L17.2388 15.1412L17.0055 15.2759M3.50049 8L3.50049 21.2673C3.50049 22.0371 4.33382 22.5182 5.00049 22.1333L14.1192 16.9423L14.4074 16.7759" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="16" stroke-linecap="round" data-play-pause="path"></path>
  </svg>
</button>
styles.css
css
.play-pause-button {
  background-color: #000;
  border: none;
  justify-content: center;
  align-items: center;
  width: max(7.5rem, 10vw);
  height: max(7.5rem, 10vw);
  padding: 0;
  display: flex;
}

.play-pause-icon {
  width: 100%;
  height: 100%;
}
script.js
javascript
gsap.registerPlugin(MorphSVGPlugin);

function initMorphingPlayPauseToggle() {

  const playPath = "M3.5 5L3.50049 3.9468C3.50049 3.177 4.33382 2.69588 5.00049 3.08078L20.0005 11.741C20.6672 12.1259 20.6672 13.0882 20.0005 13.4731L17.2388 15.1412L17.0055 15.2759M3.50049 8L3.50049 21.2673C3.50049 22.0371 4.33382 22.5182 5.00049 22.1333L14.1192 16.9423L14.4074 16.7759";
  const pausePath = "M15.5004 4.05859V5.0638V5.58691V8.58691V15.5869V19.5869V21.2549M8.5 3.96094V10.3721V17V19L8.5 21";

  const buttonToggle = document.querySelector('[data-play-pause="toggle"]');
  const iconPath = buttonToggle.querySelector('[data-play-pause="path"]');
  let isPlaying = false;

  buttonToggle.addEventListener("click", () => {
    gsap.to(iconPath, {
      duration: 0.5,
      morphSVG: {
        type: "rotational",
        map: "complexity", // morphs based on anchor point count — fastest option
        shape: isPlaying ? playPath : pausePath,
      },
      ease: "power4.inOut",
    });
    isPlaying = !isPlaying;
  });
}

// Initialize Morphing Play/Pause Toggle
document.addEventListener('DOMContentLoaded', () => {
  initMorphingPlayPauseToggle();
});

Guide

Toggle Attribute

Add data-play-pause="toggle" to the button element that triggers the morph on click.

Path Attribute

Add data-play-pause="path" to the SVG <path> element that should morph. The script reads its current d value as the play state and morphs it to the pausePath string, then back.

Morph Settings

type: "rotational" rotates anchor points to find the best match before morphing. map: "complexity" pairs points by anchor count — the fastest mapping option. Adjust duration and ease to change the feel of the transition.

Path Customization

For custom icons, make sure the playPath variable in the script exactly matches the d attribute in your HTML. Open the SVG in a code editor, copy the d value, and paste it into the playPath and pausePath variables.

Best Practices

Works best with single-path SVGs where both states have similar point complexity. Avoid grouped shapes, masks, or clip-paths — they can cause alignment artifacts. If point counts differ significantly between states, try type: "linear" as an alternative.