<button class="button">
    <div class="icon">
        <svg viewBox="0 0 14 15">
            <line x1="5" y1="13" x2="5" y2="1"></line>
            <polyline id="tick" points="1 9.5 5 13.5 13 5.5"></polyline>
            <polyline id="normal" points="1 9.5 5 13.5 9 9.5"></polyline>
        </svg>
        <div>
            <svg viewBox="0 0 24 24"></svg>
        </div>
    </div>
    <ul>
        <li>&#68;ownload</li>
        <li>Waiting</li>
        <li>Open file</li>
    </ul>
</button>

<!-- dribbble - twitter -->
<a class="dribbble" href="https://dribbble.com/shots/9143098-Download-button" target="_blank"><img src="https://cdn.dribbble.com/assets/dribbble-ball-mark-2bd45f09c2fb58dbbfb44766d5d1d07c5a12972d602ef8b32204d28fa3dda554.svg" alt=""></a>
<a class="twitter" target="_blank" href="https://twitter.com/aaroniker_me"><svg xmlns="http://www.w3.org/2000/svg" width="72" height="72" viewBox="0 0 72 72"><path d="M67.812 16.141a26.246 26.246 0 0 1-7.519 2.06 13.134 13.134 0 0 0 5.756-7.244 26.127 26.127 0 0 1-8.313 3.176A13.075 13.075 0 0 0 48.182 10c-7.229 0-13.092 5.861-13.092 13.093 0 1.026.118 2.021.338 2.981-10.885-.548-20.528-5.757-26.987-13.679a13.048 13.048 0 0 0-1.771 6.581c0 4.542 2.312 8.551 5.824 10.898a13.048 13.048 0 0 1-5.93-1.638c-.002.055-.002.11-.002.162 0 6.345 4.513 11.638 10.504 12.84a13.177 13.177 0 0 1-3.449.457c-.846 0-1.667-.078-2.465-.231 1.667 5.2 6.499 8.986 12.23 9.09a26.276 26.276 0 0 1-16.26 5.606A26.21 26.21 0 0 1 4 55.976a37.036 37.036 0 0 0 20.067 5.882c24.083 0 37.251-19.949 37.251-37.249 0-.566-.014-1.134-.039-1.694a26.597 26.597 0 0 0 6.533-6.774z"></path></svg></a>
.button {
    --background: #2B3044;
    --text: #fff;
    --icon: #fff;
    --icon-success: #16BF78;
    display: flex;
    outline: none;
    border: 0;
    padding: 0 22px 0 16px;
    min-width: 147px;
    overflow: hidden;
    cursor: pointer;
    border-radius: 9px;
    background: var(--background);
    transition: transform .2s;
    &:active {
        transform: scale(.95);
    }
    ul {
        margin: 0;
        padding: 13px 0;
        list-style: none;
        text-align: center;
        position: relative;
        backface-visibility: hidden;
        font-size: 16px;
        font-weight: 500;
        line-height: 25px;
        color: var(--text);
        li {
            &:not(:first-child) {
                top: var(--t, 13px);
                left: 0;
                position: absolute;
            }
            &:nth-child(2) {
                --t: 64px;
            }
            &:nth-child(3) {
                --t: 115px;
            }
        }
    }
    .icon {
        width: 24px;
        height: 24px;
        position: relative;
        display: inline-block;
        vertical-align: top;
        margin: 14px 10px 0 0;
        transform: translateY(calc(var(--y, 0) * 1px));
        svg {
            width: var(--w, 14px);
            height: var(--h, 15px);
            display: block;
            fill: none;
            stroke: var(--s, var(--icon));
            stroke-width: var(--sw, 2);
            stroke-linejoin: round;
            stroke-linecap: round;
        }
        & > svg,
        div {
            left: var(--l, 7px);
            top: var(--t, 2px);
            position: absolute;
        }
        & > svg {
            transform: translateY(calc(var(--y, 0) * 1px));
            polyline,
            line {
                stroke-dasharray: var(--a, 12px);
                stroke-dashoffset: var(--o, 0);
                stroke: var(--s, var(--icon));
                transition: stroke-dashoffset var(--d, .15s), stroke .4s;
            }
            polyline {
                --d: .25s;
                --a: 17px;
                --o: 5.5px;
            }
        }
        div {
            --w: 24px;
            --h: 24px;
            --l: 0;
            --t: 8px;
            --sw: 1.5;
        }
    }
    &.loading {
        ul {
            animation: text 1750ms linear forwards 100ms;
        }
        &.complete {
            .icon {
                svg {
                    line {
                        --o: 12px;
                    }
                    polyline {
                        --o: 0;
                        --s: var(--icon-success);
                    }
                }
            }
        }
    }
}

@keyframes text {
    18%,
    82% {
        transform: translateY(-100%);
    }
    100% {
        transform: translateY(-200%);
    }
}

html {
    box-sizing: border-box;
    -webkit-font-smoothing: antialiased;
}

* {
    box-sizing: inherit;
    &:before,
    &:after {
        box-sizing: inherit;
    }
}

// Center & dribbble
body {
    min-height: 100vh;
    display: flex;
    font-family: 'Roboto', Arial;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    background: #F6F8FF;
    .dribbble {
        position: fixed;
        display: block;
        right: 20px;
        bottom: 20px;
        img {
            display: block;
            height: 28px;
        }
    }
    .twitter {
        position: fixed;
        display: block;
        right: 64px;
        bottom: 14px;
        svg {
            width: 32px;
            height: 32px;
            fill: #1da1f2;
        }
    }
}
View Compiled
const $ = (s, o = document) => o.querySelector(s);
const $$ = (s, o = document) => o.querySelectorAll(s);

$$('.button').forEach(button => {

    let icon = $('.icon', button),
        arrow = $('.icon > svg', button),
        line = $('.icon div svg', button),
        svgPath = new Proxy({
            y: null
        }, {
            set(target, key, value) {
                target[key] = value;
                if(target.y !== null) {
                    line.innerHTML = getPath(target.y, .25, null);
                }
                return true;
            },
            get(target, key) {
                return target[key];
            }
        });

    svgPath.y = 12;

    button.addEventListener('click', e => {
        if(!button.classList.contains('loading')) {

            button.classList.add('loading');

            gsap.timeline({
                repeat: 2
            }).to(svgPath, {
                y: 17,
                duration: .17,
                delay: .03
            }).to(svgPath, {
                y: 12,
                duration: .3,
                ease: Elastic.easeOut.config(1, .35)
            });

            gsap.timeline({
                repeat: 2,
                repeatDelay: .1,
                onComplete() {
                    gsap.to(arrow, {
                        '--y': -17.5,
                        duration: .4
                    });
                    setTimeout(() => button.classList.add('complete'), 200);
                }
            }).to(arrow, {
                '--y': 9,
                duration: .2
            }).to(arrow, {
                '--y': -9,
                duration: .2
            });

            gsap.timeline().to(icon, {
                y: 4,
                duration: .2
            }).to(icon, {
                y: 8,
                duration: .2,
                delay: .2
            }).to(icon, {
                y: 12,
                duration: .2,
                delay: .2
            }).to(icon, {
                y: 18,
                duration: .2,
                delay: .2
            });

        }
        e.preventDefault();
    });

});

function getPoint(point, i, a, smoothing) {
    let cp = (current, previous, next, reverse) => {
            let p = previous || current,
                n = next || current,
                o = {
                    length: Math.sqrt(Math.pow(n[0] - p[0], 2) + Math.pow(n[1] - p[1], 2)),
                    angle: Math.atan2(n[1] - p[1], n[0] - p[0])
                },
                angle = o.angle + (reverse ? Math.PI : 0),
                length = o.length * smoothing;
            return [current[0] + Math.cos(angle) * length, current[1] + Math.sin(angle) * length];
        },
        cps = cp(a[i - 1], a[i - 2], point, false),
        cpe = cp(point, a[i - 1], a[i + 1], true);
    return `C ${cps[0]},${cps[1]} ${cpe[0]},${cpe[1]} ${point[0]},${point[1]}`;
}

function getPath(update, smoothing, pointsNew) {
    let points = pointsNew ? pointsNew : [
            [2, 12],
            [12, update],
            [22, 12]
        ],
        d = points.reduce((acc, point, i, a) => i === 0 ? `M ${point[0]},${point[1]}` : `${acc} ${getPoint(point, i, a, smoothing)}`, '');
    return `<path d="${d}" />`;
}

External CSS

  1. https://fonts.googleapis.com/css?family=Roboto:400,500,700&amp;display=swap

External JavaScript

  1. https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/gsap-latest-beta.min.js