Copied!
It's on your clipboard.
You’ve been offline for 0 second. Please check your Internet connection.

Help Us Improve

Found an issue or have an idea? Let us know.
Select all that apply...
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Emoji Wave on Form Submission
Preview
Overview

A short visual burst of floating images that rise and drift smoothly across the screen on form submission. Adds a lively, rewarding touch to confirm success and fades away cleanly after the animation.

Documentation
Integration
Walkthrough

Copy To Elementor
Setup: External Scripts

Language
Copy
<!-- GSAP core + Physics2D (add these once per project) -->
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/Physics2DPlugin.min.js"></script>
Step 1: Add Custom CSS

Language
Copy
<style>
.ou-emoji-img {
  position: fixed;
  top: 0;
  left: 0;
  will-change: transform;
  transform-origin: center;
  image-rendering: auto;
  user-select: none;
  pointer-events: none;
  z-index: 9999;
  backface-visibility: hidden;
}
</style>
Step 2: Add custom Javascript

Language
Copy
window.addEventListener("load", () => {
  if (typeof gsap === "undefined" || typeof Physics2DPlugin === "undefined") return;
  gsap.registerPlugin(Physics2DPlugin);

  // customize animation settings here
  const settings = {
    images: [
      "https://showcase.oura.supply/wp-content/uploads/2025/10/Love-Emoji.svg",
      "https://showcase.oura.supply/wp-content/uploads/2025/10/Playful-Emoji.svg",
      "https://showcase.oura.supply/wp-content/uploads/2025/10/Cheeky-Emoji.svg"
    ],
    total: 40, // controls how many images appear
    size: { min: 180, max: 280 }, // sets min/max image size
    speed: { min: 3.5, max: 5.5 }, // defines travel duration
    velocity: { min: 700, max: 1000 }, // controls launch power
    gravity: { min: -1500, max: -1000 }, // defines motion arc
    drift: 80 // adjusts horizontal movement
  };

  function spawnImageWave() {
    const { images, total, size, speed, velocity, gravity, drift } = settings;
    const screenWidth = window.innerWidth;
    const screenHeight = window.innerHeight;

    for (let i = 0; i < total; i++) {
      const img = document.createElement("img");
      img.src = gsap.utils.random(images);
      img.classList.add("ou-float-img");

      const startX = (i / total) * screenWidth + gsap.utils.random(-100, 100);
      const startY = screenHeight + gsap.utils.random(150, 400);
      const imgSize = gsap.utils.random(size.min, size.max);
      const delay = gsap.utils.random(0, 1.2);

      gsap.set(img, {
        position: "fixed",
        width: imgSize,
        height: "auto",
        left: startX,
        top: startY,
        rotation: gsap.utils.random(-15, 15),
        zIndex: 9999,
        pointerEvents: "none"
      });

      document.body.appendChild(img);

      // subtle horizontal float
      gsap.to(img, {
        x: `+=${gsap.utils.random(-drift, drift)}`,
        repeat: -1,
        yoyo: true,
        duration: gsap.utils.random(2, 3.5),
        ease: "sine.inOut"
      });

      // upward movement and cleanup
      gsap.to(img, {
        delay,
        duration: gsap.utils.random(speed.min, speed.max),
        physics2D: {
          velocity: gsap.utils.random(velocity.min, velocity.max),
          angle: gsap.utils.random(-88, -92),
          gravity: gsap.utils.random(gravity.min, gravity.max)
        },
        rotation: gsap.utils.random(-45, 45),
        ease: "none",
        onComplete: () => img.remove()
      });
    }
  }

  // listens for form success event
  const triggerBtn = document.querySelector("#ou-image-trigger");
  const successClass = "elementor-message-success";
  const observerTimeout = 6000;

  if (!triggerBtn) return;

  triggerBtn.addEventListener("click", () => {
    let observerActive = true;

    const observer = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        mutation.addedNodes.forEach((node) => {
          if (
            observerActive &&
            node.nodeType === 1 &&
            node.classList.contains(successClass)
          ) {
            spawnImageWave();
            observer.disconnect();
            observerActive = false;
          }
        });
      });
    });

    observer.observe(document.body, { childList: true, subtree: true });

    setTimeout(() => {
      if (observerActive) observer.disconnect();
      observerActive = false;
    }, observerTimeout);
  });
});
Add Form Trigger ID

Add the ID "ou-image-trigger" to your form’s submit button so the animation runs after a successful submission.

Language
Copy

Language
Copy

Language
Copy
Publish and preview live

Some solutions only work on the live site. Always publish and test after each change, as results may not appear in the editor.

Absolutely Codefree
If you were expecting some fancy snippet, sorry. This one runs just fine on its own.
C’mon, You Got This
Do we really need to spell this one out? It’s as straightforward as it gets.
Resorce Details
Collection
Components
Category
Category
Interaction
Builder
Last Updated
October 9, 2025