---
title: "A typing animation with zero JavaScript"
url: https://sharadbapat.com/writing/pure-css-typewriter/
description: "A typewriter effect that types, pauses, deletes and starts again, built entirely in CSS. No JavaScript, no timers, no libraries."
published: 2026-08-16
author: Sharad Bapat
---

# A typing animation with zero JavaScript

16 August 2026 · Essay

Here's a small effect: a line of text that types itself out one character at a time, waits a moment, deletes itself, and is replaced by the next line, on a loop, forever. It looks like this:

*[Demo: A terminal-style box typing three lines in turn: What is 42? Then: Calculating for 7.5 million years... Then: 42: The Meaning of Life and Everything.]*

The interesting part isn't the effect. It's that there's no JavaScript anywhere in it. No `setInterval`, no timer counting characters, nothing listening for anything. It's three lines of plain text and some CSS.

## The trick is a box that grows

A typewriter effect looks like it's revealing letters one at a time. It isn't. Under the hood, the full sentence is there from the start. It's just wrapped in a box that starts at zero width, with `overflow: hidden` clipping anything past its edge. As the box's width animates from `0` to "wide enough for the whole sentence", more of the text shows, letter by letter, purely because there's more room for it.

It's the same idea as sliding a piece of paper out from under a ruler. The words underneath don't move. The ruler does.

The blinking cursor is a second, much smaller trick: a solid border on the right edge of the same box, with its colour animated between visible and transparent on a fast, even loop.

## Why it doesn't look smooth, on purpose

If you just animate `width` from `0` to `13ch` over a couple of seconds, the browser does what it always does with animation: it interpolates smoothly, so the box eases open like a fade rather than typing. That's the wrong shape. Real typing moves in discrete jumps: one character appears, then nothing, then the next.

CSS has a tool for exactly this. Instead of the default smooth timing, you tell the animation to move in a fixed number of even `steps()`, one per character. Land on a value, hold it, jump to the next, hold again. That's what reads as typing rather than a box resizing.

## Three lines sharing one clock

The trickiest part isn't any single line typing. It's getting three lines to take turns without any JavaScript coordinating them. Each phrase gets its own looping animation, all set to the same total duration, and each is only visible and expanded during its own slice of that shared timeline: the first third for line one, the middle third for line two, the last third for line three. Outside its slice, a phrase sits collapsed and invisible.

Run all three at once and, because they loop on identical timing, they take turns naturally. No line needs to know about the others. They're each watching the same clock and reacting to a different part of it.

## What this is actually good for

A loading state, a rotating "here's what this does" line, a bit of personality on an otherwise static page: anywhere a small animated flourish is worth more than the cost of shipping JavaScript to produce it. It also respects people who've asked their operating system for reduced motion with a single `prefers-reduced-motion` media query. The demo above swaps to a still punchline for them.

The honest tradeoff: this only works because the text and its timing are known ahead of time. The widths and step counts are tuned to these exact phrases. It's not a general-purpose typewriter you hand arbitrary text at runtime; for that, you'd want JavaScript. It's for a small, fixed number of lines you're happy to tune once and forget, which, for a flourish like this, is most of the time.
