How to Create a JavaScript Typewriter Using Vanilla JavaScript

on in JavaScript DOM
Last modified on

This was done for a client, and I do not recommend it as it uses setTimeout(). Anything using setTimeout() or setInterval() slows down the page. Still, as it was a temporary landing page, this is how I approached it.

Demo

See a live demo here.

HTML

The HTML structure is pretty simple and all details are contained into data parameters. I’d say it’s relatively safe for SEO.

<h2 class="header-text">
    roo: <span class="typewrite" data-period="2000" data-type='[ "Is Your Site Slow", "Has Your Site Been Hacked", "Do You Need Website Maintenance", "Do You Want Better Page Speed" ]'>
        <span class="wrap"></span>
    </span>
</h2>

JavaScript

<script>
let TxtType = function (el, toRotate, period) {
    this.toRotate = toRotate;
    this.el = el;
    this.loopNum = 0;
    this.period = parseInt(period, 10) || 2000;
    this.txt = "";
    this.tick();
    this.isDeleting = false;
};

TxtType.prototype.tick = function () {
    let i = this.loopNum % this.toRotate.length;
    let fullTxt = this.toRotate[i];

    if (this.isDeleting) {
        this.txt = fullTxt.substring(0, this.txt.length - 1);
    } else {
        this.txt = fullTxt.substring(0, this.txt.length + 1);
    }

    this.el.innerHTML = `<span class="wrap">${this.txt}</span>`;

    let that = this;
    let delta = 100 - Math.random() * 100;
    if (this.isDeleting) {
        delta /= 4;
    }

    if (!this.isDeleting && this.txt === fullTxt) {
        delta = this.period;
        this.isDeleting = true;
    } else if (this.isDeleting && this.txt === "") {
        this.isDeleting = false;
        this.loopNum++;
        delta = 1000 / 60;
    }

    setTimeout(() => {
        that.tick();
    }, delta);
};

document.addEventListener('DOMContentLoaded', () => {
    let elements = document.getElementsByClassName('typewrite');
    for (let i = 0; i < elements.length; i++) {
        let toRotate = elements[i].dataset.type;
        let period = elements[i].dataset.period;

        if (toRotate) {
            new TxtType(elements[i], JSON.parse(toRotate), period);
        }
    }
});
</script>

CSS

Most of this is for demo purposes only, you only need the animation and the pseudo-element:

.header-text {
    font-family: "Poppins";
    font-weight: 500;
}

.typewrite > .wrap {
    position: relative;
    font-weight: 300;
}
.typewrite > .wrap:after {
    content: "?";
    color: orange;
    font-weight: 500;

    position: absolute;
    animation: blinkerText 1s linear infinite;
}

@keyframes blinkerText {
    50% {
        opacity: 0;
    }
}

Related posts