JSFiddle - React, Tailwind, and code Playground

by Pankaj Patel

HTML

<span class="element"></span><span class="typed-cursor">|</span>

CSS

.typed-cursor{
    opacity: 1;
    -webkit-animation: blink 0.7s infinite;
    -moz-animation: blink 0.7s infinite;
    animation: blink 0.7s infinite;
}
@keyframes blink{
    0% { opacity:1; }
    50% { opacity:0; }
    100% { opacity:1; }
}
@-webkit-keyframes blink{
    0% { opacity:1; }
    50% { opacity:0; }
    100% { opacity:1; }
}
@-moz-keyframes blink{
    0% { opacity:1; }
    50% { opacity:0; }
    100% { opacity:1; }
}

JavaScript

"use strict"

const sleep = delay => new Promise(resolve => setTimeout(resolve, delay))
const humanize = speed => Math.round(Math.random() * (100 - 30)) + speed
async function typed(opts) {
	let {
		strings, 
		elm, 
		backDelay = 500,
		eraseSpeed = 10,
		typeSpeed = 30,	
		loop = false
	} = opts
	
	do {
		let last = strings.length
		let index = 0

		for (let string of strings) {
			index++

			for (let character of string) {
				await sleep(humanize(typeSpeed))
				elm.innerText += character
			}

			if (!loop && last == index) return

			await sleep(backDelay)

			while (string) {
				await sleep(humanize(eraseSpeed))
				elm.innerText = string = string.slice(0, -1)
			}
		}
	} while (loop)
}

typed({
	elm: document.querySelector(".element"),
	strings: ['You know', 'What you', 'have to do'],
	// loop: false <-- default
}).then(() => console.log('done with animation'))