Posted in Buttons
10119
8:51 am, October 4, 2021

Animated Success Button with Confetti

What is Animated Success Button with Confetti?

This is a success button, well an action button that has a loading function as well as a success message and confetti when clicked, all contained within the button. 

What can i use this button for?

This could be used to give some more flair to your contact form or any other button where a loading and success maybe required.

Should I use the Animated Success Button?

A lot of code is required to give this button all of the features so you may want to consider just using a normal button for your project, but if you want to give the user a lot of feedback and animations this one could be good for your next project. 

Conclusion

This button is an awesome example of animations used on one element to provide the user great feedback and a sense of a reward on clicking the button. 

Original Codepen Source

Thanks to the author zanewesley, this code comes from the Animated Button pen on Codepen.

Animated Success Button with Confetti Demo

View Demo Full Screen View Demo New Tab

Animated Success Button with Confetti Code

HTML

<button id="button" class="ready" onclick="clickButton();">
  
  <div class="message submitMessage">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13 12.2">
      <polyline stroke="currentColor" points="2,7.1 6.5,11.1 11,7.1 "/>
      <line stroke="currentColor" x1="6.5" y1="1.2" x2="6.5" y2="10.3"/>
    </svg> <span class="button-text">Click Me!</span>
  </div>
  
  <div class="message loadingMessage">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 19 17">
      <circle class="loadingCircle" cx="2.2" cy="10" r="1.6"/>
      <circle class="loadingCircle" cx="9.5" cy="10" r="1.6"/>
      <circle class="loadingCircle" cx="16.8" cy="10" r="1.6"/>
    </svg>
  </div>
  
  <div class="message successMessage">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13 11">
      <polyline stroke="currentColor" points="1.4,5.8 5.1,9.5 11.6,2.1 "/>
    </svg> <span class="button-text">Success</span>
  </div>
</button>

<canvas id="canvas"></canvas>

CSS

@keyframes loading {
  0% {
    cy: 10;
  }
  25% {
    cy: 3;
  }
  50% {
    cy: 10;
  }
}
body {
  -webkit-font-smoothing: antialiased;
  background-color: #f4f7ff;
}

canvas {
  height: 100vh;
  pointer-events: none;
  position: fixed;
  width: 100%;
  z-index: 2;
}

button {
  background: none;
  border: none;
  color: #f4f7ff;
  cursor: pointer;
  font-family: 'Roboto', Arial;
  font-size: 14px;
  font-weight: 500;
  height: 40px;
  left: 50%;
  outline: none;
  overflow: hidden;
  padding: 0 10px;
  position: fixed;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 190px;
  z-index: 1;
}
button::before {
  background: #1f2335;
  border-radius: 50px;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.4) inset;
  content: '';
  display: block;
  height: 100%;
  margin: 0 auto;
  position: relative;
  transition: width 0.2s cubic-bezier(0.39, 1.86, 0.64, 1) 0.3s;
  width: 100%;
}

button.ready .submitMessage svg {
  opacity: 1;
  top: 1px;
  transition: top .4s ease 600ms, opacity .3s linear 600ms;
}
button.ready .submitMessage .button-text span {
  top: 0;
  opacity: 1;
  transition: all 0.2s ease calc(var(--dr) + 600ms);
}

button.loading::before {
  transition: width .3s ease;
  width: 80%;
}
button.loading .loadingMessage {
  opacity: 1;
}
button.loading .loadingCircle {
  animation-duration: 1s;
  animation-iteration-count: infinite;
  animation-name: loading;
  cy: 10;
}

button.complete .submitMessage svg {
  top: -30px;
  transition: none;
}
button.complete .submitMessage .button-text span {
  top: -8px;
  transition: none;
}
button.complete .loadingMessage {
  top: 80px;
}
button.complete .successMessage .button-text span {
  left: 0;
  opacity: 1;
  transition: all 0.2s ease calc(var(--d) + 1000ms);
}
button.complete .successMessage svg {
  stroke-dashoffset: 0;
  transition: stroke-dashoffset .3s ease-in-out 1.4s;
}

.button-text span {
  opacity: 0;
  position: relative;
}

.message {
  left: 50%;
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 100%;
}

.message svg {
  display: inline-block;
  fill: none;
  margin-right: 5px;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-width: 2;
}

.submitMessage .button-text span {
  top: 8px;
  transition: all 0.2s ease var(--d);
}
.submitMessage svg {
  color: #5c86ff;
  margin-left: -1px;
  opacity: 0;
  position: relative;
  top: 30px;
  transition: top .4s ease, opacity .3s linear;
  width: 14px;
}

.loadingMessage {
  opacity: 0;
  transition: opacity 0.3s linear 0.3s, top 0.4s cubic-bezier(0.22, 0, 0.41, -0.57);
}
.loadingMessage svg {
  fill: #5c86ff;
  margin: 0;
  width: 22px;
}

.successMessage .button-text span {
  left: 5px;
  transition: all 0.2s ease var(--dr);
}
.successMessage svg {
  color: #5cffa1;
  stroke-dasharray: 20;
  stroke-dashoffset: 20;
  transition: stroke-dashoffset .3s ease-in-out;
  width: 14px;
}

.loadingCircle:nth-child(2) {
  animation-delay: 0.1s;
}

.loadingCircle:nth-child(3) {
  animation-delay: 0.2s;
}

Javascript

const button = document.getElementById('button');
		var disabled = false;
		const canvas = document.getElementById('canvas');
		const ctx = canvas.getContext('2d');
		canvas.width = window.innerWidth;
		canvas.height = window.innerHeight;
		let cx = ctx.canvas.width / 2;
		let cy = ctx.canvas.height / 2;

		// add Confetti/Sequince objects to arrays to draw them
		let confetti = [];
		let sequins = [];

		// ammount to add on each button press
		const confettiCount = 20;
		const sequinCount = 10;

		// "physics" variables
		const gravityConfetti = 0.3;
		const gravitySequins = 0.55;
		const dragConfetti = 0.075;
		const dragSequins = 0.02;
		const terminalVelocity = 3;

		// colors, back side is darker for confetti flipping
		const colors = [
		  { front : '#7b5cff', back: '#6245e0' }, // Purple
		  { front : '#b3c7ff', back: '#8fa5e5' }, // Light Blue
		  { front : '#5c86ff', back: '#345dd1' }  // Darker Blue
		];

		// helper function to pick a random number within a range
		randomRange = (min, max) => Math.random() * (max - min) + min;

		// helper function to get initial velocities for confetti
		// this weighted spread helps the confetti look more realistic
		initConfettoVelocity = (xRange, yRange) => {
		  const x = randomRange(xRange[0], xRange[1]);
		  const range = yRange[1] - yRange[0] + 1;
		  let y = yRange[1] - Math.abs(randomRange(0, range) + randomRange(0, range) - range);
		  if (y >= yRange[1] - 1) {
		    // Occasional confetto goes higher than the max
		    y += (Math.random() < .25) ? randomRange(1, 3) : 0;
		  }
		  return {x: x, y: -y};
		}

		// Confetto Class
		function Confetto() {
		  this.randomModifier = randomRange(0, 99);
		  this.color = colors[Math.floor(randomRange(0, colors.length))];
		  this.dimensions = {
		    x: randomRange(5, 9),
		    y: randomRange(8, 15),
		  };
		  this.position = {
		    x: randomRange(canvas.width/2 - button.offsetWidth/4, canvas.width/2 + button.offsetWidth/4),
		    y: randomRange(canvas.height/2 + button.offsetHeight/2 + 8, canvas.height/2 + (1.5 * button.offsetHeight) - 8),
		  };
		  this.rotation = randomRange(0, 2 * Math.PI);
		  this.scale = {
		    x: 1,
		    y: 1,
		  };
		  this.velocity = initConfettoVelocity([-9, 9], [6, 11]);
		}
		Confetto.prototype.update = function() {
		  // apply forces to velocity
		  this.velocity.x -= this.velocity.x * dragConfetti;
		  this.velocity.y = Math.min(this.velocity.y + gravityConfetti, terminalVelocity);
		  this.velocity.x += Math.random() > 0.5 ? Math.random() : -Math.random();
		  
		  // set position
		  this.position.x += this.velocity.x;
		  this.position.y += this.velocity.y;

		  // spin confetto by scaling y and set the color, .09 just slows cosine frequency
		  this.scale.y = Math.cos((this.position.y + this.randomModifier) * 0.09);    
		}

		// Sequin Class
		function Sequin() {
		  this.color = colors[Math.floor(randomRange(0, colors.length))].back,
		  this.radius = randomRange(1, 2),
		  this.position = {
		    x: randomRange(canvas.width/2 - button.offsetWidth/3, canvas.width/2 + button.offsetWidth/3),
		    y: randomRange(canvas.height/2 + button.offsetHeight/2 + 8, canvas.height/2 + (1.5 * button.offsetHeight) - 8),
		  },
		  this.velocity = {
		    x: randomRange(-6, 6),
		    y: randomRange(-8, -12)
		  }
		}
		Sequin.prototype.update = function() {
		  // apply forces to velocity
		  this.velocity.x -= this.velocity.x * dragSequins;
		  this.velocity.y = this.velocity.y + gravitySequins;
		  
		  // set position
		  this.position.x += this.velocity.x;
		  this.position.y += this.velocity.y;
		}

		// add elements to arrays to be drawn
		initBurst = () => {
		  for (let i = 0; i < confettiCount; i++) {
		    confetti.push(new Confetto());
		  }
		  for (let i = 0; i < sequinCount; i++) {
		    sequins.push(new Sequin());
		  }
		}

		// draws the elements on the canvas
		render = () => {
		  ctx.clearRect(0, 0, canvas.width, canvas.height);
		  
		  confetti.forEach((confetto, index) => {
		    let width = (confetto.dimensions.x * confetto.scale.x);
		    let height = (confetto.dimensions.y * confetto.scale.y);
		    
		    // move canvas to position and rotate
		    ctx.translate(confetto.position.x, confetto.position.y);
		    ctx.rotate(confetto.rotation);

		    // update confetto "physics" values
		    confetto.update();
		    
		    // get front or back fill color
		    ctx.fillStyle = confetto.scale.y > 0 ? confetto.color.front : confetto.color.back;
		    
		    // draw confetto
		    ctx.fillRect(-width / 2, -height / 2, width, height);
		    
		    // reset transform matrix
		    ctx.setTransform(1, 0, 0, 1, 0, 0);

		    // clear rectangle where button cuts off
		    if (confetto.velocity.y < 0) {
		      ctx.clearRect(canvas.width/2 - button.offsetWidth/2, canvas.height/2 + button.offsetHeight/2, button.offsetWidth, button.offsetHeight);
		    }
		  })

		  sequins.forEach((sequin, index) => {  
		    // move canvas to position
		    ctx.translate(sequin.position.x, sequin.position.y);
		    
		    // update sequin "physics" values
		    sequin.update();
		    
		    // set the color
		    ctx.fillStyle = sequin.color;
		    
		    // draw sequin
		    ctx.beginPath();
		    ctx.arc(0, 0, sequin.radius, 0, 2 * Math.PI);
		    ctx.fill();

		    // reset transform matrix
		    ctx.setTransform(1, 0, 0, 1, 0, 0);

		    // clear rectangle where button cuts off
		    if (sequin.velocity.y < 0) {
		      ctx.clearRect(canvas.width/2 - button.offsetWidth/2, canvas.height/2 + button.offsetHeight/2, button.offsetWidth, button.offsetHeight);
		    }
		  })

		  // remove confetti and sequins that fall off the screen
		  // must be done in seperate loops to avoid noticeable flickering
		  confetti.forEach((confetto, index) => {
		    if (confetto.position.y >= canvas.height) confetti.splice(index, 1);
		  });
		  sequins.forEach((sequin, index) => {
		    if (sequin.position.y >= canvas.height) sequins.splice(index, 1);
		  });

		  window.requestAnimationFrame(render);
		}

		// cycle through button states when clicked
		clickButton = () => {
		  if (!disabled) {
		    disabled = true;
		    // Loading stage
		    button.classList.add('loading');
		    button.classList.remove('ready');
		    setTimeout(() => {
		      // Completed stage
		      button.classList.add('complete');
		      button.classList.remove('loading');
		      setTimeout(() => {
		        window.initBurst();
		        setTimeout(() => {
		          // Reset button so user can select it again
		          disabled = false;
		          button.classList.add('ready');
		          button.classList.remove('complete');
		        }, 4000);
		      }, 320);
		    }, 1800);
		  }
		}

		// re-init canvas if the window size changes
		resizeCanvas = () => {
		  canvas.width = window.innerWidth;
		  canvas.height = window.innerHeight;
		  cx = ctx.canvas.width / 2;
		  cy = ctx.canvas.height / 2;
		}

		// resize listenter
		window.addEventListener('resize', () => {
		  resizeCanvas();
		});

		// click button on spacebar or return keypress
		document.body.onkeyup = (e) => {
		  if (e.keyCode == 13 || e.keyCode == 32) {
		    clickButton();
		  }
		}

		// Set up button text transition timings on page load
		textElements = button.querySelectorAll('.button-text');
		textElements.forEach((element) => {
		  characters = element.innerText.split('');
		  let characterHTML = '';
		  characters.forEach((letter, index) => {
		    characterHTML += `<span class="char${index}" style="--d:${index * 30}ms; --dr:${(characters.length - index - 1) * 30}ms;">${letter}</span>`;
		  })
		  element.innerHTML = characterHTML;
		})

		// kick off the render loop
		render();

External Link for Animated Success Button with Confetti

No Items Found.

Add Comment
Type in a Nick Name here
 
Search Code
Search Code by entering your search text above.
Welcome to CSSBundle.com

Hi there and welcome to CSSBundle. Here at CSS Bundle we aim to find the best css and javascript bundles and demos and add them here to make them easy to find all in one place.

If you would like to stay up to date with our latest updates you can subscribe to our mailing list where we will send you one email per week with the latest updates, no spam emails just the latest updates.

Random Quote


Latest Code
css animations Falling Stars CSS Animation html Video different sources on screen sizes video embed html responsive css animations Animated Triangles on Canvas JS HTML HTML Canvas Instant colour fill with HTML Canvas javascript Transform Text into Images using SnapText JS CSS Tools Fancy Border Radius CSS Generator Tool - spin animation keyframes CSS Tools CSS Drop Filter Shadow Creator CSS Slider A CSS and HTML Only Carousel Slider CSS Z-Index Z-Index Code Front - CSS to change z-index when element is active sections section with image to the right text to the left gradient Sections Two Clickable Logo Promo Box Section Foundation HTML CSS Sections Inline Contact Form Formatting HTML CSS Sections Overview full width section in Poppins font with light gray background using foundation Interactive Images Map Image with Easy Dots and Titles using only CSS HTML Sections Social Header Links easy Drop in Code with Font Awesome Icons Sections Responsive Friendly Subscribe to our Newsletter Section CSS Tips Create a button with CSS, HTML and Center it! CSS Text Formatting Truncate Text to an amount of lines using line-clamp CSS Positions Item Positioning in CSS CSS Tips Draw a Circle in CSS css animations Magical Text Effect Bootstrap 4.2 Kitchen Sink CSS Frameworks Make your site look like windows 7 CSS Backgrounds Fancy up your banner image hero sections using overlay gradients CSS Modal Floating Modal Message Fixed on the Bottom of the Screen CSS Modal Create a modal with only CSS css grid display items in a css grid CSS Text Effects Using the selection selector to change the default highlight color Text Truncate your Text with CSS CSS Cursors Change your cursor into an Emoji Cursor or Image Cursor CSS How to Center Everything or Anything with CSS CSS Animations Smooth Scrolling with just CSS CSS Animations Radial Glow under cursor on box hover over effect CSS Shadows Using a filter drop shadow for transparent images CSS Animations Pure CSS 3D Flipping Book with Animations CSS Create a checkerboard background pattern with CSS CSS Animations button animations hover and fill animation CSS Animations button on focus swing animation CSS Animations Animated Button Border when Active Quick CSS create a border with top triangle in css CSS Animations Single Element CSS Spinners CSS Animations CSS Shake - Shake up your elements CSS Framework NES-style(8bit-like) CSS Framework CSS Tips Why to use a CSS Reset? Web Developer Checklists Front-End Checklist Icons Font Awesome Icons CSS Animation Animate Stuff with Animate.css CSS Animations Check Wave Click a Checkbox and Watch the Animation Animation Cloudy spiral animation with CSS3 Notifications Toast Messages and Notifications Standalone Library no JQuery - notify.js