16 CSS Bounce Animations03 / 16

Pure CSSMIT licensed

Success Checkmark Pop

A payment / form-submit success confirmation — mint circle scales up with elastic overshoot, then the checkmark draws in via stroke-dashoffset. Stripe checkout / Apple Pay / Shopify payment success aesthetic (mint #d1fae5 success surface + emerald #065f46 check). The bounce reads as "you're good." The classic two-stage cascade — circle pops, then check draws — that every well-designed confirmation UI uses.

Published

Live Demo
Try it

The code

<div class="bn-03" role="status" aria-live="polite">
  <span class="bn-03__circle" aria-hidden="true">
    <svg viewBox="0 0 52 52" width="72" height="72" aria-hidden="true">
      <path class="bn-03__check-path" d="M14 27 l8 8 l16 -18" fill="none" stroke="currentColor" stroke-width="4.5" stroke-linecap="round" stroke-linejoin="round"/>
    </svg>
  </span>
  <p class="bn-03__label">Payment received</p>
</div>
.bn-03 {
  --page-bg: #f0fdf4;
  --ink: #052e1a;
  --sub: #4b6b58;
  --mint: #d1fae5;
  --emerald: #065f46;
  --emerald-soft: rgba(6,95,70,.24);
  font-family: -apple-system,BlinkMacSystemFont,'SF Pro Rounded','Inter','Segoe UI',sans-serif;
  width: 100%;
  min-height: 100vh;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 24px;
  padding: 32px;
  background: radial-gradient(60% 60% at 50% 50%, rgba(16,185,129,.12) 0%, transparent 60%), var(--page-bg);
  color: var(--ink);
  text-align: center;
}

.bn-03 *,
.bn-03 *::before,
.bn-03 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.bn-03 ::selection {
  background: var(--emerald);
  color: #fff;
}

.bn-03__circle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 120px;
  height: 120px;
  border-radius: 50%;
  background: var(--mint);
  color: var(--emerald);
  transform: scale(0);
  animation: bn-03-pop .5s cubic-bezier(.34,1.56,.64,1) forwards;
  box-shadow: 0 20px 40px -10px var(--emerald-soft);
}

@keyframes bn-03-pop {
  0% {
    transform: scale(0);
  }

  40% {
    transform: scale(1.15);
  }

  70% {
    transform: scale(.95);
  }

  100% {
    transform: scale(1);
  }
}

.bn-03__check-path {
  stroke-dasharray: 44;
  stroke-dashoffset: 44;
  animation: bn-03-draw .4s cubic-bezier(.65,0,.35,1) .3s forwards;
}

@keyframes bn-03-draw {
  to {
    stroke-dashoffset: 0;
  }
}

.bn-03__label {
  font-size: 1.1rem;
  font-weight: 800;
  letter-spacing: -.01em;
  color: var(--ink);
  opacity: 0;
  animation: bn-03-fade .3s ease-out .55s forwards;
}

@keyframes bn-03-fade {
  from {
    opacity: 0;
    transform: translateY(6px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .bn-03__circle,
    .bn-03__check-path,
    .bn-03__label {
    animation: none!important;
  }

  .bn-03__circle {
    transform: scale(1)!important;
  }

  .bn-03__check-path {
    stroke-dashoffset: 0!important;
  }

  .bn-03__label {
    opacity: 1!important;
    transform: none!important;
  }
}
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Bounce Animation from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Success Checkmark Pop
Source: https://codefronts.com/motion/css-bounce-animation/success-checkmark-pop/

A payment / form-submit success confirmation — mint circle scales up with elastic overshoot, then the checkmark draws in via stroke-dashoffset. Stripe checkout / Apple Pay / Shopify payment success aesthetic (mint #d1fae5 success surface + emerald #065f46 check). The bounce reads as "you're good." The classic two-stage cascade — circle pops, then check draws — that every well-designed confirmation UI uses.
## HTML
```html
<div class="bn-03" role="status" aria-live="polite">
  <span class="bn-03__circle" aria-hidden="true">
    <svg viewBox="0 0 52 52" width="72" height="72" aria-hidden="true">
      <path class="bn-03__check-path" d="M14 27 l8 8 l16 -18" fill="none" stroke="currentColor" stroke-width="4.5" stroke-linecap="round" stroke-linejoin="round"/>
    </svg>
  </span>
  <p class="bn-03__label">Payment received</p>
</div>
```
## CSS
```css
.bn-03 {
  --page-bg: #f0fdf4;
  --ink: #052e1a;
  --sub: #4b6b58;
  --mint: #d1fae5;
  --emerald: #065f46;
  --emerald-soft: rgba(6,95,70,.24);
  font-family: -apple-system,BlinkMacSystemFont,'SF Pro Rounded','Inter','Segoe UI',sans-serif;
  width: 100%;
  min-height: 100vh;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 24px;
  padding: 32px;
  background: radial-gradient(60% 60% at 50% 50%, rgba(16,185,129,.12) 0%, transparent 60%), var(--page-bg);
  color: var(--ink);
  text-align: center;
}

.bn-03 *,
.bn-03 *::before,
.bn-03 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.bn-03 ::selection {
  background: var(--emerald);
  color: #fff;
}

.bn-03__circle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 120px;
  height: 120px;
  border-radius: 50%;
  background: var(--mint);
  color: var(--emerald);
  transform: scale(0);
  animation: bn-03-pop .5s cubic-bezier(.34,1.56,.64,1) forwards;
  box-shadow: 0 20px 40px -10px var(--emerald-soft);
}

@keyframes bn-03-pop {
  0% {
    transform: scale(0);
  }

  40% {
    transform: scale(1.15);
  }

  70% {
    transform: scale(.95);
  }

  100% {
    transform: scale(1);
  }
}

.bn-03__check-path {
  stroke-dasharray: 44;
  stroke-dashoffset: 44;
  animation: bn-03-draw .4s cubic-bezier(.65,0,.35,1) .3s forwards;
}

@keyframes bn-03-draw {
  to {
    stroke-dashoffset: 0;
  }
}

.bn-03__label {
  font-size: 1.1rem;
  font-weight: 800;
  letter-spacing: -.01em;
  color: var(--ink);
  opacity: 0;
  animation: bn-03-fade .3s ease-out .55s forwards;
}

@keyframes bn-03-fade {
  from {
    opacity: 0;
    transform: translateY(6px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .bn-03__circle,
    .bn-03__check-path,
    .bn-03__label {
    animation: none!important;
  }

  .bn-03__circle {
    transform: scale(1)!important;
  }

  .bn-03__check-path {
    stroke-dashoffset: 0!important;
  }

  .bn-03__label {
    opacity: 1!important;
    transform: none!important;
  }
}
```

How this works

The circle uses transform: scale(0) initially and animates to scale(1) via @keyframes bn-03-pop with 4 stops — 0% scale(0) → 40% scale(1.15) → 70% scale(.95) → 100% scale(1). Duration 500ms with cubic-bezier(.34, 1.56, .64, 1) — the elastic overshoot cubic-bezier that's become the industry standard for "success" moments (Stripe, Shopify, Apple Pay).

The checkmark is a pure SVG <path> drawn with stroke-dasharray + stroke-dashoffset — starts hidden (offset = full path length), animates to stroke-dashoffset: 0 over 400ms AFTER the circle pops (via animation-delay: .3s). This creates the classic "circle appears, then check draws itself in" cascade.

The demo shows the check as the hero at 120px, with a single-line label "Payment received" below it — enough to signal the use case without a full receipt/order-number/CTA layout burying the effect.

Make it yours

  • Change color for different success types — mint for payment/order (default), sky-blue for account created, purple for magic-link sent, amber for saved-to-wishlist. Match to your semantic color palette.
  • For high-stakes contexts (medical procedure booking, legal signature) reduce overshoot — replace cubic-bezier(.34, 1.56, .64, 1) with cubic-bezier(.22, 1, .36, 1) (no overshoot, smooth deceleration). Elastic bounces feel wrong on serious confirmations.
  • Add confetti burst around the checkmark for order-success moments — pure CSS with 12 <span> elements at radial angles + --angle/--dist CSS variables. See css-modals collection Demo 15 for the pattern.
  • For Tailwind: animate-[bn03pop_.5s_cubic-bezier(.34,1.56,.64,1)_both] + register keyframes in tailwind.config.js. See FAQ #4.
  • Chain a follow-up scale-and-drift-up on the copy below the check — start opacity 0 + translateY(8px) then fade+rise into position via animation-delay: .5s. Creates a mini-cascade of "check pops in, then text arrives."

Gotchas — read before shipping

  • The SVG check draw MUST use stroke-dashoffset — NOT width, height, or d attribute animation. stroke-dashoffset is a compositor-safe property; d attribute animation triggers full re-paint of the path on every frame.
  • The circle pop and check draw must CASCADE — check draws AFTER circle pops. If both animate at the same time, users see a partial check inside a growing circle which reads as broken. Use animation-delay: .3s on the check to gate it.
  • For accessibility, announce the success via aria-live='polite' on a wrapper — screen-reader users can't see the checkmark. "Payment successful" is the required announcement pattern.
  • The 1.15 overshoot scale is INTENTIONAL — a smooth 0-to-1 scale feels flat and mechanical. The 15% overshoot is what makes it read as "physical arrival with delight" instead of "UI blipping into existence."
  • Do NOT loop this animation — success confirmations are one-shot events. If your CSS accidentally loops (missing animation-fill-mode: forwards or iteration-count: 1), the check pulses forever which reads as "trying to succeed" instead of "succeeded."
  • For payment context specifically, this UI must appear ONLY after the backend confirms the payment intent — never optimistically. Showing success before Stripe's confirmCardPayment resolves creates "I paid but was charged twice" support tickets.
  • For prefers-reduced-motion, skip the scale bounce + check draw — show the checkmark in its final state instantly. The information (success) is preserved; only the celebration motion is disabled.

Browser support

ChromeSafariFirefoxEdge
45+10+40+45+

transform + stroke-dashoffset + @keyframes. Universal, GPU-accelerated.

Techniques used in this demo

Search CodeFronts

Loading…