21 CSS Button Hover Effects

Typewriter Retype

Text erases and retypes itself character by character on hover — like a live terminal cursor.

CSS + JS MIT licensed

Typewriter Retype the 12th of 21 designs in the 21 CSS Button Hover Effects collection. The design pairs CSS styling with a small amount of JavaScript for interactivity. Copy the HTML, CSS and JavaScript panels below into your project — the JS is self-contained, has zero dependencies, and is safe to drop into any framework (React, Vue, Svelte, plain HTML). The design honours prefers-reduced-motion and uses real semantic markup, so it ships accessibility-ready out of the box.

Live preview

Open in playground

The code

<button class="bhe-12__btn">
  <span class="bhe-12__text">console.log()</span>
  <span class="bhe-12__cursor"></span>
</button>
.bhe-12__btn {
  padding: 12px 32px;
  font-size: 13.5px;
  font-weight: 500;
  border-radius: 8px;
  cursor: pointer;
  letter-spacing: 0.02em;
  color: inherit;
  background: transparent;
}

.bhe-12__btn {
  font-family: monospace;
}
.bhe-12__cursor {
  display: inline-block;
  width: 2px;
  height: 13px;
  background: currentColor;
  margin-left: 2px;
  vertical-align: middle;
  opacity: 0;
}
.bhe-12__btn:hover .bhe-12__cursor {
  animation: blink 0.6s step-end infinite;
}
@keyframes blink {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .bhe-12__btn,
  .bhe-12__btn * {
    animation: none !important;
  }
}
document.querySelectorAll(".bhe-12__btn").forEach(function (btn) {
  const txt = btn.querySelector(".bhe-12__text");
  if (!txt) return;
  const full = txt.textContent;
  btn.addEventListener("mouseenter", function () {
    let i = full.length;
    const erase = setInterval(function () {
      txt.textContent = full.slice(0, --i);
      if (i === 0) {
        clearInterval(erase);
        retype();
      }
    }, 55);
    function retype() {
      let j = 0;
      const write = setInterval(function () {
        txt.textContent = full.slice(0, ++j);
        if (j === full.length) clearInterval(write);
      }, 55);
    }
  });
});

Search CodeFronts

Loading…