Close Menu

    Subscribe to Updates

    Get the latest creative news from FooBar about art, design and business.

    What's Hot

    How to make Animated Download Button in HTML CSS & JS

    21 November 2025

    How to make Password Input Light in HTML CSS & JavaScript

    18 November 2025

    How to make I love you heart card Animation in HTML CSS & JavaScript

    14 November 2025
    Facebook X (Twitter) Instagram YouTube Telegram Threads
    Coding StellaCoding Stella
    • Home
    • Blog
    • HTML & CSS
      • Login Form
    • JavaScript
    • Hire us!
    Coding StellaCoding Stella
    Home - JavaScript - How to make Animated Download Button in HTML CSS & JS
    JavaScript

    How to make Animated Download Button in HTML CSS & JS

    Coding StellaBy Coding Stella21 November 2025Updated:21 November 2025No Comments7 Mins Read
    Share Facebook Twitter Pinterest LinkedIn Tumblr Reddit Email WhatsApp Copy Link

    Let’s create an Animated Download Button using HTML, CSS, and JavaScript. This project will feature a stylish button that animates when clicked, giving users a smooth and interactive download experience.

    We’ll use:

    • HTML to structure the download button.
    • CSS to style it and add cool animations like progress or loading effects.
    • JavaScript to trigger and control the animation when the button is clicked.

    This project is perfect for learning how to combine functionality with design, creating buttons that are both useful and visually appealing. Let’s dive in and make your downloads look awesome! ⬇️💻

    HTML :

    This code creates an animated download button using HTML, SVG icons, and GSAP for smooth animations. The button shows a download arrow, a parachute animation, a circular loading shape, and a percentage counter that updates during the animation. When the download completes, the text switches to “Complete.” The SVG shapes handle the visuals, GSAP controls the motion and morphing effects, and the external CSS file manages styling like colors, sizes, and transitions.

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <title>Animated Download Button | @coding.stella </title>
      <link rel="stylesheet" href="https://public.codepenassets.com/css/reset-2.0.min.css">
      <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Inter:400,500,600,700&amp;display=swap'>
      <link rel="stylesheet" href="./style.css">
    
    </head>
    
    <body>
      <button class="dl-parachute">
        <span class="success">Complete</span>
        <div class="arrow">
          <svg class="base" viewBox="0 0 48 48">
            <path
              d="M23.191 46.588C23.379 46.847 23.68 47 24 47C24.32 47 24.621 46.847 24.809 46.588L40.809 24.588C41.03 24.284 41.062 23.881 40.892 23.546C40.72 23.211 40.376 23 40 23H31V2C31 1.448 30.552 1 30 1H18C17.448 1 17 1.448 17 2V23H7.99999C7.62399 23 7.27999 23.211 7.10899 23.546C6.93799 23.881 6.96999 24.284 7.19199 24.588L23.191 46.588Z" />
          </svg>
          <svg class="parachute" viewBox="0 0 28 32">
            <path
              d="M27.5 20.2542C26.9093 23.9345 24.4253 32 14 32C3.57466 32 1.09075 23.9345 0.5 20.2542L0.502764 19.04L12.756 0H15.244L27.4972 19.04C27.4972 19.4629 27.5 20.2542 27.5 20.2542ZM25.8243 19.0357L14.933 3.0248V18.5033C15.9843 18.5979 16.8727 18.8393 17.7587 19.0801C18.887 19.3867 20.0115 19.6923 21.4639 19.6923C22.9864 19.6923 24.6154 19.3565 25.8243 19.0357ZM13.067 18.5033V3.0248L2.17572 19.0357C3.38456 19.3565 5.01356 19.6923 6.5361 19.6923C7.98852 19.6923 9.113 19.3867 10.2413 19.0801C11.1273 18.8393 12.0157 18.5979 13.067 18.5033Z" />
          </svg>
        </div>
        <svg class="circle" viewBox="0 0 280 124">
          <path
            d="M81.5 62C81.5006 29.6913 107.691 3.50059 140 3.5C172 3.5 198.505 30.1029 198.5 62C198.495 94.1709 172.67 120.225 140.5 120.5C108.054 120.777 81.4994 94.447 81.5 62Z" />
        </svg>
        <svg class="line" viewBox="0 0 280 128"></svg>
        <span class="number"><span>0</span>%</span>
      </button>
    
      <script src='https://cdnjs.cloudflare.com/ajax/libs/gsap/3.4.0/gsap.min.js'></script>
      <script src='https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/MorphSVGPlugin3.min.js'></script>
      <script src="./script.js"></script>
    
    </body>
    
    </html>

    CSS :

    This CSS controls the entire download button animation using custom variables. It sets colors, positions, rotation, opacity, and movement for the arrow, parachute, circle, progress line, and success text. The button is styled with no default borders, centered SVG icons, and smooth transforms handled by variables that JavaScript updates during the animation. The circle and line SVGs form the loading shape, the parachute appears beneath the arrow and animates with scale and opacity, and the number and success text fade and slide into place. The body is centered to display the button cleanly on a plain background.

    .dl-parachute {
      --color-text: #275EFE;
      --color-icon: #275EFE;
      --color-line: #275EFE;
      --svg-y: 0px;
      --arrow-x: 0px;
      --arrow-y: 2px;
      --arrow-r: 0deg;
      --line-opacity: 0;
      --circle-opacity: 1;
      --parachute-o: 1;
      --parachute-y: 0px;
      --parachute-s: 0;
      --line-progress-o: 0;
      --line-progress: 260px;
      --success-y: 12px;
      --success-o: 0;
      --number-y: 12px;
      --number-o: 0;
      -webkit-tap-highlight-color: transparent;
      -webkit-appearance: none;
      outline: none;
      background: none;
      border: none;
      padding: 0;
      margin: 0;
      cursor: pointer;
      font-size: 14px;
      font-weight: 600;
      font-family: "Inter";
      position: relative;
      width: 120px;
      height: 120px;
    }
    
    .dl-parachute svg {
      display: block;
      pointer-events: none;
    }
    
    .dl-parachute svg.circle,
    .dl-parachute svg.line {
      width: 280px;
      height: 124px;
      position: absolute;
      left: -80px;
      stroke-width: 3px;
      stroke-linecap: round;
      stroke: var(--color-line);
      fill: none;
    }
    
    .dl-parachute svg.circle {
      top: -2px;
      opacity: var(--circle-opacity);
      transform: translateY(var(--svg-y)) rotate(180deg);
    }
    
    .dl-parachute svg.line {
      height: 128px;
      bottom: -65px;
      opacity: var(--line-opacity);
    }
    
    .dl-parachute svg.line .progress {
      stroke-width: 6px;
      stroke-dasharray: 260px;
      opacity: var(--line-progress-o);
      stroke-dashoffset: var(--line-progress);
    }
    
    .dl-parachute .arrow {
      position: absolute;
      left: 36px;
      top: 36px;
      transform: translate(var(--arrow-x), var(--arrow-y)) rotate(var(--arrow-r));
    }
    
    .dl-parachute .arrow .base {
      fill: var(--color-icon);
      width: 48px;
      height: 48px;
    }
    
    .dl-parachute .arrow .parachute {
      position: absolute;
      width: 28px;
      height: 32px;
      fill: var(--color-icon);
      left: 10px;
      bottom: -26px;
      transform-origin: 50% 0%;
      opacity: var(--parachute-o);
      transform: translateY(var(--parachute-y)) scale(var(--parachute-s));
    }
    
    .dl-parachute .number,
    .dl-parachute .success {
      position: absolute;
      left: 0;
      right: 0;
      top: var(--t, 144px);
      text-align: center;
      color: var(--color-text);
      opacity: var(--o, var(--number-o));
      transform: translateY(var(--y, var(--number-y)));
    }
    
    .dl-parachute .success {
      --t: 12px;
      --o: var(--success-o);
      --y: var(--success-y);
    }
    
    html {
      box-sizing: border-box;
      -webkit-font-smoothing: antialiased;
    }
    
    * {
      box-sizing: inherit;
    }
    
    *:before,
    *:after {
      box-sizing: inherit;
    }
    
    body {
      overflow: hidden;
      min-height: 100vh;
      font-family: "Inter";
      display: flex;
      justify-content: center;
      align-items: center;
      background: white;
    }
    
    body .dribbble {
      position: fixed;
      display: block;
      right: 20px;
      bottom: 20px;
    }
    
    body .dribbble img {
      display: block;
      width: 76px;
    }
    
    body .twitter {
      position: fixed;
      display: block;
      right: 112px;
      bottom: 14px;
    }
    
    body .twitter svg {
      width: 24px;
      height: 24px;
      fill: white;
    }

    JavaScript:

    This JavaScript controls all button animations using GSAP. When the button is clicked, it prevents double clicks, changes the SVG circle into a straight line, moves the arrow up and down, shows the progress line, and animates the percentage from 0 to 100. It also scales and hides the parachute, rotates the arrow with keyframes, and updates the curved line using a Proxy that redraws the SVG path. After the loading finishes, the arrow morphs into a tick shape and the success text fades in. The helper functions getPoint and getPath generate smooth curved SVG lines for the progress animation.

    gsap.registerPlugin(MorphSVGPlugin)
    
    document.querySelectorAll('.dl-parachute').forEach(button => {
        let circle = button.querySelector('.circle path'),
            arrow = button.querySelector('.arrow path'),
            line = new Proxy({
                y: null
            }, {
                set(target, key, value) {
                    target[key] = value
                    if (target.y !== null) {
                        button.querySelector('.line').innerHTML = getPath(target.y, .2)
                    }
                    return true
                },
                get(target, key) {
                    return target[key]
                }
            }),
            number = button.querySelector('.number span'),
            count = { number: 0 }
        line.y = 64.5
    
        button.addEventListener('click', e => {
            e.preventDefault()
    
            if (button.classList.contains('active')) {
                return
            }
    
            button.classList.add('active')
    
            gsap.timeline().to(circle, {
                morphSVG: 'M10 120.5C11.5 120.5 29.1914 120.5 61.5 120.5C78.5 120.5 108.054 120.777 140.5 120.5C172.67 120.225 201.5 120.5 218.5 120.5C250.397 120.5 268.5 120.5 270 120.5',
                duration: .15,
                onComplete() {
                    gsap.set(button, {
                        '--circle-opacity': 0,
                        '--line-opacity': 1
                    })
                }
            }).to(button, {
                '--svg-y': '120px',
                '--arrow-y': '44px',
                duration: .15
            }, 0).to(button, {
                '--arrow-y': '-72px',
                duration: .3,
                ease: 'power1.out'
            }).to(button, {
                '--arrow-y': '40px',
                '--line-progress': '0px',
                duration: 3,
                delay: .15,
                onStart() {
                    gsap.to(button, {
                        '--line-progress-o': 1
                    })
                }
            }).to(count, {
                number: 100,
                roundProps: 'number',
                duration: 3,
                onUpdate: () => number.innerHTML = count.number
            }, .6).to(button, {
                '--parachute-o': 0,
                '--parachute-y': '12px',
                duration: .2
            }).to(button, {
                '--arrow-y': '20px',
                duration: .7,
                ease: 'elastic.out(1, .8)'
            })
    
            gsap.to(button, {
                '--parachute-s': 1,
                '--number-o': 1,
                '--number-y': '0px',
                duration: .2,
                delay: .4
            })
    
            gsap.to(button, {
                ease: 'linear',
                keyframes: [{
                    '--arrow-r': '190deg',
                    '--arrow-x': '-12px',
                    duration: .6,
                    delay: .6
                }, {
                    '--arrow-r': '170deg',
                    '--arrow-x': '12px',
                    duration: .6
                }, {
                    '--arrow-r': '185deg',
                    '--arrow-x': '-6px',
                    duration: .7
                }, {
                    '--arrow-r': '180deg',
                    '--arrow-x': '0px',
                    duration: .5
                }]
            })
    
            gsap.to(button, {
                '--arrow-r': '180deg',
                duration: .3
            })
    
            gsap.to(line, {
                keyframes: [{
                    y: 24,
                    duration: .15,
                    delay: .125
                }, {
                    y: 64.5,
                    duration: .8,
                    ease: 'elastic.out(1, .5)'
                }]
            })
    
            gsap.to(button, {
                '--success-o': 1,
                '--success-y': '0px',
                duration: .25,
                delay: 3.825
            })
    
            gsap.to(arrow, {
                morphSVG: 'M28.5858 10.0503C29.3669 9.2692 30.6332 9.2692 31.4142 10.0503L42.5 21.136C43.8807 22.5167 43.8807 24.7553 42.5 26.136C41.1193 27.5168 38.8807 27.5167 37.5 26.136L31.4142 20.0502C30.6332 19.2692 29.3669 19.2692 28.5858 20.0503L10.5 38.136C9.11931 39.5167 6.88073 39.5168 5.50002 38.136C4.11931 36.7553 4.11931 34.5167 5.50002 33.136L28.5858 10.0503Z',
                duration: .2,
                delay: 3.8
            })
    
        })
    })
    
    
    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) {
        let points = [
            [10, 64.5],
            [140, update],
            [270, 64.5]
        ],
            d = points.reduce((acc, point, i, a) => i === 0 ? `M ${point[0]},${point[1]}` : `${acc} ${getPoint(point, i, a, smoothing)}`, '');
        return `<path d="${d}" /><path class="progress" d="${d}" />`;
    }

    In conclusion, creating an Animated Download Button using HTML, CSS, and JavaScript is a fun and practical project that adds interactivity and style to your web pages. By combining animations and logic, we’ve built a button that feels responsive and modern ⚡

    If you run into any problems with your project, worry not. The remedy is just a click away – Download the source code and confront your coding challenges with enthusiasm. Enjoy your coding adventure!

    Animation CSS Animation
    Share. Copy Link Twitter Facebook LinkedIn Email WhatsApp
    Previous ArticleHow to make Password Input Light in HTML CSS & JavaScript
    Coding Stella
    • Website

    Related Posts

    JavaScript

    How to make Password Input Light in HTML CSS & JavaScript

    18 November 2025
    JavaScript

    How to make I love you heart card Animation in HTML CSS & JavaScript

    14 November 2025
    HTML & CSS

    How to make Husky Dog Animation using HTML and CSS

    10 November 2025
    Add A Comment
    Leave A Reply Cancel Reply

    Trending Post

    Master Frontend in 100 Days Ebook

    2 March 202430K Views

    How to make Modern Login Form using HTML & CSS | Glassmorphism

    11 January 202428K Views

    How to make I love you Animation in HTML CSS & JavaScript

    14 February 202422K Views

    How to make Valentine’s Day Card using HTML & CSS

    13 February 202414K Views
    Follow Us
    • Instagram
    • Facebook
    • YouTube
    • Twitter
    ads
    Featured Post

    How to create Glowing Neon Cursor using HTML CSS and JS

    2 August 2025

    Frontend Developer Roadmap 2025: The Complete Guide

    31 January 2025

    What is HTML? Understanding the Basics of Hypertext Markup Language

    31 January 2024

    How to make Happy birthday cake Animation using HTML & CSS

    29 May 2025
    Latest Post

    How to make Animated Download Button in HTML CSS & JS

    21 November 2025

    How to make Password Input Light in HTML CSS & JavaScript

    18 November 2025

    How to make I love you heart card Animation in HTML CSS & JavaScript

    14 November 2025

    How to make Husky Dog Animation using HTML and CSS

    10 November 2025
    Facebook X (Twitter) Instagram YouTube
    • About Us
    • Privacy Policy
    • Return and Refund Policy
    • Terms and Conditions
    • Contact Us
    • Buy me a coffee
    © 2025 Coding Stella. Made with 💙 by @coding.stella

    Type above and press Enter to search. Press Esc to cancel.

    Ad Blocker Enabled!
    Ad Blocker Enabled!
    Looks like you're using an ad blocker. We rely on advertising to help fund our site.
    Okay! I understood