Components / Motion / Typewriter
Typewriter beta
A sentence that types itself, deletes itself, and types the next one — with a patient caret.
Blocks compose
<p class="k-type" data-type data-phrases='["a dashboard", "a settings page", "a pricing table", "an app shell"]' aria-label="Blocks compose a dashboard, a settings page, a pricing table, an app shell." style="font-size:21px;font-weight:600;letter-spacing:-.02em"> Blocks compose <span aria-hidden="true"><span data-type-out></span><span class="k-type-caret"></span></span> </p>
/* KATA Typewriter — types, rests, deletes, repeats. */
.k-type{font-family:var(--k-font)}
.k-type-caret{display:inline-block;width:2.5px;height:1.02em;margin-inline-start:2px;background:var(--k-ink);vertical-align:-0.14em;animation:k-type-blink 1.05s steps(1) infinite}
@keyframes k-type-blink{50%{opacity:0}}
@media (prefers-reduced-motion:reduce){.k-type-caret{animation:none}}
// KATA Typewriter — types, rests, deletes, moves on.
document.querySelectorAll('[data-type]').forEach(function (el) {
var out = el.querySelector('[data-type-out]');
var phrases = [];
try { phrases = JSON.parse(el.getAttribute('data-phrases') || '[]'); } catch (e) { phrases = []; }
if (!phrases.length) return;
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) { out.textContent = phrases[0]; return; }
var pi = 0, ci = 0, deleting = false;
function tick() {
var full = phrases[pi];
if (deleting) {
ci--;
out.textContent = full.slice(0, ci);
if (ci === 0) { deleting = false; pi = (pi + 1) % phrases.length; setTimeout(tick, 420); return; }
setTimeout(tick, 34);
} else {
ci++;
out.textContent = full.slice(0, ci);
if (ci === full.length) { deleting = true; setTimeout(tick, 1850); return; }
setTimeout(tick, 68 + Math.random() * 60);
}
}
tick();
});
Installation
CLI
node kata-ui.mjs add typewriter
Writes the part’s CSS and JS into your project. New to the CLI? See the CLI doc.
Manual
- Load
tokens.cssonce, before any part. - Copy the CSS tab into your stylesheet.
- Copy the HTML where it belongs. The part has a script — include it after the markup; it initializes itself.
Usage
Phrases live in the data-phrases attribute as a JSON list. The rhythm is the design: type at reading-aloud speed, rest on the finished line, delete faster than you typed. One typewriter per page — two is a typing pool.
Accessibility
The animation is a performance of text that must also exist statically: the element carries an aria-label with the full sentence, the animated text is aria-hidden, and under prefers-reduced-motion the first phrase simply stands typed. Never put information only in a later phrase.
Anatomy
The public surface of this part, read from its own source. Class names are the API — the CSS tab above is the full contract.
.k-type | class |
.k-type-caret | class |
data-type | data hook |
data-phrases | data hook |
data-type-out | data hook |
aria-label | ARIA |
aria-hidden | ARIA |
Related parts
Accordion Gallery beta
Five scenes in a row; the one you touch opens up and tells its caption.
Aurora beta
A slow wash of color behind a hero — the accent and the core, drifting under glass.
Beam border beta
A single point of light travels the edge of a card. The beam is the core color — the one accent, in motion.
Blur In beta
Words arrive out of focus and sharpen one after another, like eyes adjusting.