Default example

Some facts about cats:

Typing delay examples

Default (100ms)

Some facts about cats:

500ms

Some facts about cats:

0ms

Some facts about cats:

Typing variation examples

Default (100ms)

Some facts about cats:

500ms

Some facts about cats:

0ms

Some facts about cats:

0ms with typingDelay = 0ms

Some facts about cats:

Untyping delay examples

Default (100ms)

Some facts about cats:

500ms

Some facts about cats:

0ms

Some facts about cats:

Delay before typing examples

Default (1600ms)

Some facts about cats:

10000ms

Some facts about cats:

0ms

Some facts about cats:

Delay after typing examples

Default (3000ms)

Some facts about cats:

10000ms

Some facts about cats:

0ms

Some facts about cats:

No untyping example

Some facts about cats:

No cursor example

Some facts about cats:

Cursor symbol examples with UTF-8 emoji

Typing - 👉; untyping - 👈; blinking - ✋

Some facts about cats:

Custom cursor examples

Custom cursor demo

Some facts about cats:

You can implement custom cursors using event callbacks, like so:

customCursorTE.onBeforeTyping(() => {
  customCursorExample[1].classList.remove("idle");
});

customCursorTE.onAfterTyping(() => {
  customCursorExample[1].classList.add("idle");
});

customCursorTE.onBeforeUntyping(() => {
  customCursorExample[1].classList.remove("idle");
});

customCursorTE.onAfterUntyping(() => {
  customCursorExample[1].classList.add("idle");
});

Here customCursorExample[1] is our cursor element from this HTML:

<div class="typing-container">
  Some facts about cats: <span></span><span class="cursor idle"></span>
</div>

And the CSS for the cursor:

.cursor {
  background-color: #00ffff;
  display: inline-block;
  width: 10px;
  height: 1.4em;
  vertical-align: middle;
  height: 1em;
}

.cursor.idle {
  animation: idleCursorAnimation 2s infinite;
}

With animation:

@keyframes idleCursorAnimation {
  0% {
    background-color: #22c55e;
  }
  50% {
    background-color: #f43f5e;
  }
  100% {
    background-color: #22c55e;
  }
}

Cursor overflow examples

Here the cursor jumps to the next line:

Some facts about cats:

And here it doesn't, with some CSS:

.cursor {
  margin-left: -10px;
  translate: 100% 0;
}
Some facts about cats:

Note the cursor extending over the container's edge; unfortunately, this is a drawback of current solution.

The container width should be set to contain entire string without cursor, if not - use resize

Some usecases

Name input placeholder tip

Here we pause typing when input is focused, and we hide the placehlder with CSS so it doesn't interfere with actual input value.

Here's JS:

const nameInputExample = document.querySelector(
  "#name-input-ex input"
)!;

const nameInputExampleTE = new TypingEffect(
  [
    "Mick Jagger",
    "Freddie Mercury",
    "Jimi Hendrix",
    "David Bowie",
    "Kurt Cobain",
    "Jonathan David Douglas 'Jon' Lord",
  ],
  (string) => {
    nameInputExample.setAttribute("placeholder", string);
  }
).start();

nameInputExample.addEventListener("focus", () => {
  nameInputExampleTE.pause();
});

nameInputExample.addEventListener("blur", () => {
  nameInputExampleTE.resume();
});

And CSS:

input {
  padding: 6px 12px;
  font-size: 1em;
}

input::placeholder {
  opacity: 0.5;
  color: currentColor;
}

input:focus::placeholder {
  opacity: 0;
}

Layout shift

The problem:

This example demonstrates the layout shift, which can occur when setting element contend. Here the container's min-height is unset, unlike in other examples, and width is intentionally small to demonstrate the shift.

Some facts about cats:

Some long important text about cat history, that user is trying to read. Cats have a fascinating history that dates back thousands of years. Originating in ancient Egypt, they were revered as sacred animals and often depicted in hieroglyphs. Over time, cats became valued for their hunting abilities, helping to control pests in human settlements. During the Middle Ages in Europe, cats were associated with superstitions but eventually regained favor as cherished companions. Today, cats are one of the most popular pets worldwide, known for their independent yet affectionate nature.

This block and it's padding simulate additional content.

Additional content and spacing are required to demonstrate the shift effectively; since it needs scroll NEITHER to be at 0%, 100%, NOR at he end of typing contaier to be noticeable.

The dynamic solution â„–1:

Some facts about cats:

Some long important text about cat history, that user is trying to read. Cats have a fascinating history that dates back thousands of years. Originating in ancient Egypt, they were revered as sacred animals and often depicted in hieroglyphs. Over time, cats became valued for their hunting abilities, helping to control pests in human settlements. During the Middle Ages in Europe, cats were associated with superstitions but eventually regained favor as cherished companions. Today, cats are one of the most popular pets worldwide, known for their independent yet affectionate nature.

This block and it's padding simulate additional content.

This solution uses hidden element with longest string in the set as it's content, and CSS position to overlap the elements.

Here, we add a wrapper element, and filler, which will dictate the height of our typing-container:

<div class="typing-container-position-wrap">
  <div class="filler"></div>
  <div class="typing-container">
    Some facts about cats: <span></span>
  </div>
</div>

Position typing-container on top of filler, and hide the latter. It is important for filler and typing-container to have identical styles such as width, text-size, line-height, paddings and others that may influence the height of an element. I recommend setting a height for the filler element so that it doesn't jitter as much on load.

.typing-container-position-wrap {
  position: relative;
}

.typing-container-position-wrap .filler {
  visibility: hidden;
  max-width: 400px;
  height: 150px;
}

.typing-container-position-wrap .typing-container {
  position: absolute;
  top: 0;
} 

And JS:

// Find the longest string in array
const layoutShiftExample_longestString = layoutShiftExampleStrigs.reduce(
  (longest, current) => {
    return current.length > longest.length ? current : longest;
  },
  ""
);

// Select filler element
const layoutShiftExample_solution1_filler =
  document.querySelector(
    "#problem-layout-shift .dynamic-solution-position .filler"
);

// Set filler content
requestAnimationFrame(() => {
  layoutShiftExample_solution1_filler.style.height = "auto";
  layoutShiftExample_solution1_filler.innerText =
    "Some facts about cats: " + layoutShiftExample_longestString + "|";
});

Setting the content and height within requestAnimationFrame is recommended, because it helps the browser to schedule this update before paint.

Or you can achieve similar result with grid areas:

.typing-container-position-wrap {
  display: grid;
  grid-template-areas: "overlap";
}

.typing-container-position-wrap .filler {
  grid-area: overlap;
}

.typing-container-position-wrap .typing-container {
  grid-area: overlap;
}