Chat bot typing Animation JS

by anoopsuda

HTML

<div class="chat-box">

  <!-- HEADER -->
  <div class="header">
    <div class="header-icon"></div>
    InnoBot
    <div class="close"></div>
  </div>

  <!-- MESSAGE AREA -->
  <div class="messages">
    <div id="msg1" class="bubble typing"></div>
    <div id="msg2" class="bubble typing"></div>

    <div id="btns" class="btns">
      <button class="yes">Yes</button>
      <button class="no">No</button>
    </div>
  </div>
</div>

CSS

body {
  margin: 0;
  background: #f6f2fb;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  font-family: Arial, sans-serif;
}

/* CHAT POPUP */
.chat-box {
  width: 360px;
  background: #ffffff;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 4px 25px rgba(0,0,0,0.15);
  border: 1px solid #e0d2f5;
  position: relative;
  height:350px;
}

/* HEADER BAR */
.header {
  height: 55px;
  background: linear-gradient(90deg,#7a36e2,#9932f0);
  display: flex;
  align-items: center;
  padding: 0 15px;
  color: white;
  font-size: 18px;
  font-weight: 600;
}

/* Header Icon (square) */
.header-icon {
  width: 24px;
  height: 24px;
  background: #fff;
  border-radius: 5px;
  margin-right: 10px;
}

/* Close button */
.close {
  margin-left: auto;
  width: 20px;
  height: 20px;
  position: relative;
}
.close::before,
.close::after {
  content: "";
  position: absolute;
  width: 20px;
  height: 2px;
  background: white;
  top: 9px;
  left: 0;
}
.close::before { transform: rotate(45deg); }
.close::after { transform: rotate(-45deg); }

/* MESSAGE AREA */
.messages {
  padding: 20px;
}

/* BUBBLES */
.bubble {
  max-width: 260px;
  background: #fff;
  padding: 10px 14px;
  border-radius: 14px;
  margin-bottom: 15px;
  border: 1px solid #eee;
  opacity: 0;
  transform: translateY(25px);
  box-shadow: 0 1px 3px rgba(0,0,0,0.12);
}

/* Typing cursor */
.typing {
 /*  border-right: 2px solid #666; */
  white-space: pre-wrap;
  overflow: hidden;
}

/* slide + fade */
.fadeMoveUp {
  animation: fadeMoveUp 0.8s ease forwards;
}

@keyframes fadeMoveUp {
  0% { opacity: 0; transform: translateY(25px); }
  100% { opacity: 1; transform: translateY(0); }
}

/* BUTTONS */
.btns {
  opacity: 0;
  display: flex;
  gap: 12px;
  margin-top: 10px;
}

button {
  padding: 10px 25px;
  font-size: 16px;
  border-radius: 25px;
  cursor:...

JavaScript

/* TYPING EFFECT FUNCTION */
function typeEffect(el, text, speed, done) {
  let i = 0;
  let timer = setInterval(() => {
    el.textContent = text.slice(0, i);
    i++;
    if (i > text.length) {
      clearInterval(timer);
      el.style.borderRight = "0";
      if (done) done();
    }
  }, speed);
}

/* MAIN SEQUENCE */
window.onload = () => {
  const msg1 = document.getElementById("msg1");
  const msg2 = document.getElementById("msg2");
  const btns = document.getElementById("btns");

  // Start: First bubble appears
  msg1.classList.add("fadeMoveUp");

  setTimeout(() => {
    typeEffect(msg1, "Hi there đź‘‹", 70, () => {

      // SECOND bubble animation
      msg2.classList.add("fadeMoveUp");

      typeEffect(
        msg2,
        "I'm here to help you create your innovation story submission - quick, guided, and easy. Would you like to get started?",
        22,
        () => {
          // Show YES / NO buttons
          btns.classList.add("fadeIn");
        }
      );
    });
  }, 300);
};