JSFiddle - React, Tailwind, and code Playground

by wsgrah

HTML

<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.4.1/snap.svg-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/classie/1.0.1/classie.js"></script>
<button id="hamburger" class="menu-button">	
    <span id="morph-shape" class="morph-shape" data-morph-open="M3,20c0,0,12-4,27-4s27,4,27,4;M3,60c0,0,12,4,27,4s27-4,27-4" data-morph-close="M3,20c0,0,12,4,27,4s27-4,27-4;M3,60c0,0,12-4,27-4s27,4,27,4">
        <svg width="100%" height="100%" viewBox="0 0 60 80" preserveAspectRatio="none">
            <path d="M3,20c0,0,12,0,27,0s27,0,27,0"/>
            <line x1="3" y1="40" x2="57" y2="40"/>
		    <path d="M3,60c0,0,12,0,27,0s27,0,27,0"/>
	    </svg>
    </span>

</button>

CSS

.menu-button {
    width: 60px;
    height: 80px;
    position: relative;
    margin: 5em auto;
    display: block;
    background: none;
    outline: none;
    border: none;
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
    -webkit-tap-highlight-color: transparent;
    /* For some Androids */
}
.morph-shape {
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
}
.morph-shape svg path, .morph-shape svg line {
    stroke: #DDDCD7;
    stroke-width: 4px;
    -webkit-transition: -webkit-transform 0.3s;
    transition: transform 0.3s;
}
.menu-button--open .morph-shape svg path:first-of-type {
    -webkit-transform: translate3d(0, -8px, 0);
    transform: translate3d(0, -8px, 0);
}
.menu-button--open .morph-shape svg path:nth-of-type(2) {
    -webkit-transform: translate3d(0, 8px, 0);
    transform: translate3d(0, 8px, 0);
}

JavaScript

(function () {

    function SVGHamburger(el, options) {
        this.el = el;
        this.init();
    }

    SVGHamburger.prototype.init = function () {
        this.shapeEl = this.el.querySelector('span.morph-shape');

        var s = Snap(this.shapeEl.querySelector('svg'));
        this.pathEl1 = s.select('path:nth-of-type(1)');
        this.pathEl2 = s.select('path:nth-of-type(2)');
        this.paths = {
            reset: {
                path1: this.pathEl1.attr('d'),
                path2: this.pathEl2.attr('d')
            },
            open: this.shapeEl.getAttribute('data-morph-open').split(';'),
            close: this.shapeEl.getAttribute('data-morph-close').split(';')
        };

        this.isOpen = false;

        this.initEvents();
    };

    SVGHamburger.prototype.initEvents = function () {
        this.el.addEventListener('click', this.toggle.bind(this));
    };

    SVGHamburger.prototype.toggle = function () {
        var self = this,
            paths = this.isOpen ? this.paths.close : this.paths.open;

        if (self.isOpen) {
            setTimeout(function () {
                classie.remove(self.el, 'menu-button--open');
            }, 200);
        } else {
            setTimeout(function () {
                classie.add(self.el, 'menu-button--open');
            }, 200);
        }

        this.pathEl1.stop().animate({
            'path': paths[0]
        }, 300, mina.easeout, function () {
            self.pathEl1.stop().animate({
                'path': self.paths.reset.path1
            }, 800, mina.elastic);
        });
        this.pathEl2.stop().animate({
            'path': paths[1]
        }, 300, mina.easeout, function () {
            self.pathEl2.stop().animate({
                'path': self.paths.reset.path2
            }, 800, mina.elastic);
        });

        this.isOpen = !this.isOpen;
    };

    new SVGHamburger(document.getElementById('hamburger'));

})();