DEV Community

Cover image for JavaScript Self Typewriting
Femi Obadimu
Femi Obadimu

Posted on

JavaScript Self Typewriting

Get Pumped 😃😃😃 Guys, Because Today we'd be Exploring the world of Self Typewriting in Javascript..

I'm Pretty sure most of you must have seen it, this automated and dynamically typing stuff all over the web today.

Have you wondered how it's been made??

Well, i'm here to let you know how.
This Here explains it in Javascript.

You have to create a function , then use the this keyword attached with some attributes which does the same thing as referring to the function you just created as shown below

Best on Javascript Typewriting

Secondly, you use the prototype syntax of writing,
also all logic goes in here, e.g the length, speed of movement etc..

Best on Javascript Typewriting

Lastly , You initialize and use it on the DOM , depending on what you want or how you want to use it.

Best on Javascript Typewriting

READ, CLAP, SHARE

techforeveryone

follow for more [devsinstitute(https://instagram.com/devsinstitute)

Discussion (1)

Collapse
lukeshiru profile image
LUKESHIRU • Edited

Ideally, if you really want a class based approach, you could just use class (and maybe sprinkle with some private fields as well):

class Typewriter {
    #wordIndex = 0;
    #deleting = false;
    /** @type {string[]} */ #words = [];
    #wait = 2000;
    #strokeDelay = 50;

    /** @param {{ target: HTMLElement; strokeDelay?: number; wait?: number }} [param0] */
    constructor({ target, strokeDelay = 50, wait = 2000 }) {
        this.#strokeDelay = strokeDelay;
        this.#wait = wait;
        this.#words = target.textContent.split(" ");
        this.target = target;
        this.target.textContent = "";
        this.type = this.type.bind(this);
        this.type();
    }

    type() {
        const word = this.#words[this.#wordIndex % this.#words.length];
        const deleting = this.#deleting;
        const textContent = word.slice(
            0,
            this.target.textContent.length + (deleting ? -1 : 1)
        );
        const deleted = deleting && textContent === "";
        const typed = !deleting && textContent === word;

        this.#deleting = typed || (!deleted && deleting);
        this.#wordIndex += deleted ? 1 : 0;
        this.target.textContent = textContent;

        setTimeout(
            this.type,
            typed
                ? this.#wait
                : deleting && !deleted
                ? this.#strokeDelay / 2
                : this.#strokeDelay
        );
    }
}
Enter fullscreen mode Exit fullscreen mode

I would personally recommend to just use functions (without this and all that jazz), which is far simpler and achieves the same:

/** @param {{ target: HTMLElement; strokeDelay?: number; wait?: number }} [param0] */
const typewriter = ({ target, strokeDelay = 50, wait = 2000 }) => {
    const words = target.textContent.split(" ");
    let wordIndex = 0;
    let deleting = false;

    const type = () => {
        const word = words[wordIndex % words.length];
        const textContent = word.slice(
            0,
            target.textContent.length + (deleting ? -1 : 1)
        );
        const deleted = deleting && textContent === "";
        const typed = !deleting && textContent === word;

        deleting = typed || (!deleted && deleting);
        wordIndex += deleted ? 1 : 0;
        target.textContent = textContent;

        setTimeout(
            type,
            typed ? wait : deleting && !deleted ? strokeDelay / 2 : strokeDelay
        );
    };

    target.textContent = "";
    type();
};
Enter fullscreen mode Exit fullscreen mode

A few differences besides syntax between my approaches and yours:

  • The constructor takes an object with the options instead of multiple arguments.
  • The delay between key strokes is configurable.
  • It doesn't render a span, and instead it just updates the textContent of the target element.
  • It doesn't take a words option and instead it splits the original textContent of the element.

So to use my version you can just:

// <span>hello world</span>
typewriter({ target: document.querySelector("span") });
Enter fullscreen mode Exit fullscreen mode

Still, the important thing is not so much my implementation, but more the idea of using class instead of prototype, or better yet, use just a function without this.

Cheers!

PS: Next time you might want to add the code snippets as text instead of screenshots, and maybe a demo so folks can try out your code?