Three lines of syntax-colored JavaScript type into a small dark editor with line numbers, while the active-line highlight follows along. Colored tokens are spans inside each clipped line.
Also known as: code editor typing effect, typing code css, syntax highlighted typewriter.
<div class="txt-code-typing-animation">
<div class="txt-code-typing-animation-tab" aria-hidden="true">greet.js</div>
<div class="txt-code-typing-animation-code">
<span class="txt-code-typing-animation-ln" style="--n: 23; --d: 0.4s; --hold: 1.6s"><span class="txt-code-typing-animation-t"><span class="txt-code-typing-animation-k">const</span> <span class="txt-code-typing-animation-f">greet</span> = (name) =></span></span>
<span class="txt-code-typing-animation-ln" style="--n: 17; --d: 2s; --hold: 1.3s"> <span class="txt-code-typing-animation-t"><span class="txt-code-typing-animation-s">"Hello, "</span> + name;</span></span>
<span class="txt-code-typing-animation-ln" style="--n: 15; --d: 3.3s"><span class="txt-code-typing-animation-t"><span class="txt-code-typing-animation-f">greet</span>(<span class="txt-code-typing-animation-s">"world"</span>);</span></span>
</div>
</div>.txt-code-typing-animation {
--c: var(--txt-color, #3b82f6);
font-size: var(--txt-size, 32px);
font-family: system-ui, sans-serif;
font-weight: 700;
line-height: 1.2;
display: inline-block;
overflow: hidden;
border-radius: 0.3em;
background: #0d1117;
color: #e6edf3;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-weight: 500;
text-align: left;
box-shadow: 0 0 0 1px color-mix(in srgb, var(--c) 30%, #30363d);}
.txt-code-typing-animation-tab {
display: inline-block;
padding: 0.35em 0.9em;
font-size: 0.4em;
color: #8b949e;
background: #161b22;
box-shadow: inset 0 0.12em 0 var(--c);
}
.txt-code-typing-animation-code {
position: relative;
box-sizing: content-box;
/* gutter + the longest line, so the editor keeps its size while typing */
width: calc(3.5ch + 23ch + 0.2em);
padding: 0.6em 1.4em 0.7em 0;
font-size: 0.5em;
line-height: 1.7;
counter-reset: txt-code-typing-animation-n;
}
/* the active-line highlight steps down as each line starts */
.txt-code-typing-animation-code::before {
content: "";
position: absolute;
top: 0.6em;
left: 0;
right: 0;
height: 1.7em;
background: rgb(255 255 255 / 0.06);
box-shadow: inset 0.15em 0 0 var(--c);
animation: txt-code-typing-animation-row 3.3s step-end forwards;
}
.txt-code-typing-animation-ln {
position: relative;
display: block;
white-space: pre;
}
.txt-code-typing-animation-ln::before {
counter-increment: txt-code-typing-animation-n;
content: counter(txt-code-typing-animation-n);
display: inline-block;
width: 2ch;
margin-right: 1.5ch;
text-align: right;
color: #6e7681;
}
.txt-code-typing-animation-t {
display: inline-block;
vertical-align: top;
box-sizing: content-box;
width: 0;
overflow: hidden;
border-right: 0.12em solid transparent;
animation:
txt-code-typing-animation-type calc(var(--n) * 55ms) steps(var(--n)) var(--d) forwards,
txt-code-typing-animation-caret var(--hold) step-end var(--d);
}
.txt-code-typing-animation-ln:last-child .txt-code-typing-animation-t {
animation:
txt-code-typing-animation-type calc(var(--n) * 55ms) steps(var(--n)) var(--d) forwards,
txt-code-typing-animation-blink 1s step-end var(--d) infinite;
}
.txt-code-typing-animation-k { color: color-mix(in srgb, var(--c) 65%, #fff); }
.txt-code-typing-animation-f { color: #d2a8ff; }
.txt-code-typing-animation-s { color: #7ee787; }
@keyframes txt-code-typing-animation-type {
99.9%, to { width: calc(var(--n) * 1ch); }
}
@keyframes txt-code-typing-animation-caret {
0%, 100% { border-right-color: var(--c); }
}
@keyframes txt-code-typing-animation-blink {
0% { border-right-color: var(--c); }
50% { border-right-color: transparent; }
}
@keyframes txt-code-typing-animation-row {
0% { transform: translateY(0); }
60.6% { transform: translateY(100%); }
100% { transform: translateY(200%); }
}
@media (prefers-reduced-motion: reduce) {
.txt-code-typing-animation, .txt-code-typing-animation *, .txt-code-typing-animation::before, .txt-code-typing-animation::after, .txt-code-typing-animation *::before, .txt-code-typing-animation *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}--txt-color on the element or a parent.
Currently previewing #3b82f6.--txt-size. Every other dimension is in
em, so the whole thing scales together. Currently previewing 40px.transition or animation
shorthand. Staggered delays are relative, so they keep their rhythm.