03 / 14
All 14 in 14 CSS Typewriter Effect Designs
- 01CSS Typewriter steps() Cursor
- 02CSS Typewriter Multiline Stagger
- 03CSS Typewriter Word Swap Loop
- 04CSS Typewriter Neon Terminal
- 05CSS Typewriter clip-path Reveal
- 06CSS Typewriter SVG stroke-dashoffset
- 07CSS Typewriter Gradient Highlight Sweep
- 08CSS Typewriter Variable Font Weight Morph
- 09CSS Typewriter Split Char Stagger
- 10CSS Typewriter JS Character Injection
- 11CSS Typewriter Matrix Scramble Decode
- 12CSS Typewriter Glitch on Type
- 13CSS Typewriter Code Editor Syntax
- 14CSS Typewriter Scroll-Triggered Word Reveal
CSS Typewriter Word Swap Loop
A hero headline cycles through swappable highlight words using a single CSS keyframe that animates width and color on a looping overflow-hidden container.
Build UI like this from scratch: Flexbox, Grid, animations & responsive CSS
ZTM · The CSS Bootcamp · 30‑day money-back guarantee · Affiliate link
The code
<div class="tw-03">
<div class="tw-03__hero">
<h1 class="tw-03__headline">
We design
<span class="tw-03__slot">
<span class="tw-03__words">
<span>websites</span>
<span>products</span>
<span>systems</span>
<span>futures</span>
<span>websites</span>
</span>
</span>
</h1>
<p class="tw-03__sub">Digital craftsmanship for ambitious brands.</p>
</div>
</div><div class="tw-03">
<div class="tw-03__hero">
<h1 class="tw-03__headline">
We design
<span class="tw-03__slot">
<span class="tw-03__words">
<span>websites</span>
<span>products</span>
<span>systems</span>
<span>futures</span>
<span>websites</span>
</span>
</span>
</h1>
<p class="tw-03__sub">Digital craftsmanship for ambitious brands.</p>
</div>
</div>.tw-03,
.tw-03 *,
.tw-03 *::before,
.tw-03 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.tw-03 ::selection {
background: #f97316;
color: #1a0800;
}
.tw-03 {
--orange: #f97316;
--amber: #fbbf24;
--bg: #0c0802;
--text: #fef3c7;
--muted: #92400e;
font-family: 'Georgia', serif;
min-height: 340px;
display: flex;
align-items: center;
justify-content: center;
padding: 48px 24px;
}
.tw-03__hero {
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
}
.tw-03__headline {
font-size: clamp(1.8rem, 5vw, 3.2rem);
color: var(--text);
font-weight: 300;
line-height: 1.3;
display: flex;
align-items: baseline;
gap: 0.3em;
flex-wrap: wrap;
justify-content: center;
}
.tw-03__slot {
display: inline-block;
overflow: hidden;
height: 1.2em;
vertical-align: bottom;
border-right: 3px solid var(--orange);
background: linear-gradient(135deg, rgba(249,115,22,0.15), rgba(251,191,36,0.08));
border-radius: 4px;
padding: 0 6px;
animation: tw-03-width 8s steps(1) infinite, tw-03-blink 0.65s steps(2) infinite;
}
.tw-03__words {
display: flex;
flex-direction: column;
animation: tw-03-scroll 8s steps(4) infinite;
}
.tw-03__words span {
font-style: italic;
font-weight: 600;
color: var(--orange);
flex-shrink: 0;
height: 1.2em;
line-height: 1.2;
white-space: nowrap;
}
.tw-03__sub {
font-size: 1rem;
color: var(--muted);
letter-spacing: 0.05em;
}
@keyframes tw-03-scroll {
0% {
transform: translateY(0);
}
25% {
transform: translateY(-1.2em);
}
50% {
transform: translateY(-2.4em);
}
75% {
transform: translateY(-3.6em);
}
100% {
transform: translateY(0);
}
}
@keyframes tw-03-width {
0%,
100% {
width: 7.5ch;
}
25% {
width: 8ch;
}
50% {
width: 7.5ch;
}
75% {
width: 7.5ch;
}
}
@keyframes tw-03-blink {
0%,
100% {
border-color: var(--orange);
}
50% {
border-color: transparent;
}
}
@media (prefers-reduced-motion: reduce) {
.tw-03__slot {
animation: none;
border-right-color: var(--orange);
}
.tw-03__words {
animation: none;
}
}.tw-03,
.tw-03 *,
.tw-03 *::before,
.tw-03 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.tw-03 ::selection {
background: #f97316;
color: #1a0800;
}
.tw-03 {
--orange: #f97316;
--amber: #fbbf24;
--bg: #0c0802;
--text: #fef3c7;
--muted: #92400e;
font-family: 'Georgia', serif;
min-height: 340px;
display: flex;
align-items: center;
justify-content: center;
padding: 48px 24px;
}
.tw-03__hero {
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
}
.tw-03__headline {
font-size: clamp(1.8rem, 5vw, 3.2rem);
color: var(--text);
font-weight: 300;
line-height: 1.3;
display: flex;
align-items: baseline;
gap: 0.3em;
flex-wrap: wrap;
justify-content: center;
}
.tw-03__slot {
display: inline-block;
overflow: hidden;
height: 1.2em;
vertical-align: bottom;
border-right: 3px solid var(--orange);
background: linear-gradient(135deg, rgba(249,115,22,0.15), rgba(251,191,36,0.08));
border-radius: 4px;
padding: 0 6px;
animation: tw-03-width 8s steps(1) infinite, tw-03-blink 0.65s steps(2) infinite;
}
.tw-03__words {
display: flex;
flex-direction: column;
animation: tw-03-scroll 8s steps(4) infinite;
}
.tw-03__words span {
font-style: italic;
font-weight: 600;
color: var(--orange);
flex-shrink: 0;
height: 1.2em;
line-height: 1.2;
white-space: nowrap;
}
.tw-03__sub {
font-size: 1rem;
color: var(--muted);
letter-spacing: 0.05em;
}
@keyframes tw-03-scroll {
0% {
transform: translateY(0);
}
25% {
transform: translateY(-1.2em);
}
50% {
transform: translateY(-2.4em);
}
75% {
transform: translateY(-3.6em);
}
100% {
transform: translateY(0);
}
}
@keyframes tw-03-width {
0%,
100% {
width: 7.5ch;
}
25% {
width: 8ch;
}
50% {
width: 7.5ch;
}
75% {
width: 7.5ch;
}
}
@keyframes tw-03-blink {
0%,
100% {
border-color: var(--orange);
}
50% {
border-color: transparent;
}
}
@media (prefers-reduced-motion: reduce) {
.tw-03__slot {
animation: none;
border-right-color: var(--orange);
}
.tw-03__words {
animation: none;
}
}Here's a working CSS Typewriter Effect Design from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: CSS Typewriter Word Swap Loop
Source: https://codefronts.com/motion/css-typewriter-effect/css-typewriter-word-swap-loop/
A hero headline cycles through swappable highlight words using a single CSS keyframe that animates width and color on a looping overflow-hidden container.
## HTML
```html
<div class="tw-03">
<div class="tw-03__hero">
<h1 class="tw-03__headline">
We design
<span class="tw-03__slot">
<span class="tw-03__words">
<span>websites</span>
<span>products</span>
<span>systems</span>
<span>futures</span>
<span>websites</span>
</span>
</span>
</h1>
<p class="tw-03__sub">Digital craftsmanship for ambitious brands.</p>
</div>
</div>
```
## CSS
```css
.tw-03,
.tw-03 *,
.tw-03 *::before,
.tw-03 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.tw-03 ::selection {
background: #f97316;
color: #1a0800;
}
.tw-03 {
--orange: #f97316;
--amber: #fbbf24;
--bg: #0c0802;
--text: #fef3c7;
--muted: #92400e;
font-family: 'Georgia', serif;
min-height: 340px;
display: flex;
align-items: center;
justify-content: center;
padding: 48px 24px;
}
.tw-03__hero {
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
}
.tw-03__headline {
font-size: clamp(1.8rem, 5vw, 3.2rem);
color: var(--text);
font-weight: 300;
line-height: 1.3;
display: flex;
align-items: baseline;
gap: 0.3em;
flex-wrap: wrap;
justify-content: center;
}
.tw-03__slot {
display: inline-block;
overflow: hidden;
height: 1.2em;
vertical-align: bottom;
border-right: 3px solid var(--orange);
background: linear-gradient(135deg, rgba(249,115,22,0.15), rgba(251,191,36,0.08));
border-radius: 4px;
padding: 0 6px;
animation: tw-03-width 8s steps(1) infinite, tw-03-blink 0.65s steps(2) infinite;
}
.tw-03__words {
display: flex;
flex-direction: column;
animation: tw-03-scroll 8s steps(4) infinite;
}
.tw-03__words span {
font-style: italic;
font-weight: 600;
color: var(--orange);
flex-shrink: 0;
height: 1.2em;
line-height: 1.2;
white-space: nowrap;
}
.tw-03__sub {
font-size: 1rem;
color: var(--muted);
letter-spacing: 0.05em;
}
@keyframes tw-03-scroll {
0% {
transform: translateY(0);
}
25% {
transform: translateY(-1.2em);
}
50% {
transform: translateY(-2.4em);
}
75% {
transform: translateY(-3.6em);
}
100% {
transform: translateY(0);
}
}
@keyframes tw-03-width {
0%,
100% {
width: 7.5ch;
}
25% {
width: 8ch;
}
50% {
width: 7.5ch;
}
75% {
width: 7.5ch;
}
}
@keyframes tw-03-blink {
0%,
100% {
border-color: var(--orange);
}
50% {
border-color: transparent;
}
}
@media (prefers-reduced-motion: reduce) {
.tw-03__slot {
animation: none;
border-right-color: var(--orange);
}
.tw-03__words {
animation: none;
}
}
```Here's a working CSS Typewriter Effect Design from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: CSS Typewriter Word Swap Loop
Source: https://codefronts.com/motion/css-typewriter-effect/css-typewriter-word-swap-loop/
A hero headline cycles through swappable highlight words using a single CSS keyframe that animates width and color on a looping overflow-hidden container.
## HTML
```html
<div class="tw-03">
<div class="tw-03__hero">
<h1 class="tw-03__headline">
We design
<span class="tw-03__slot">
<span class="tw-03__words">
<span>websites</span>
<span>products</span>
<span>systems</span>
<span>futures</span>
<span>websites</span>
</span>
</span>
</h1>
<p class="tw-03__sub">Digital craftsmanship for ambitious brands.</p>
</div>
</div>
```
## CSS
```css
.tw-03,
.tw-03 *,
.tw-03 *::before,
.tw-03 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.tw-03 ::selection {
background: #f97316;
color: #1a0800;
}
.tw-03 {
--orange: #f97316;
--amber: #fbbf24;
--bg: #0c0802;
--text: #fef3c7;
--muted: #92400e;
font-family: 'Georgia', serif;
min-height: 340px;
display: flex;
align-items: center;
justify-content: center;
padding: 48px 24px;
}
.tw-03__hero {
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
}
.tw-03__headline {
font-size: clamp(1.8rem, 5vw, 3.2rem);
color: var(--text);
font-weight: 300;
line-height: 1.3;
display: flex;
align-items: baseline;
gap: 0.3em;
flex-wrap: wrap;
justify-content: center;
}
.tw-03__slot {
display: inline-block;
overflow: hidden;
height: 1.2em;
vertical-align: bottom;
border-right: 3px solid var(--orange);
background: linear-gradient(135deg, rgba(249,115,22,0.15), rgba(251,191,36,0.08));
border-radius: 4px;
padding: 0 6px;
animation: tw-03-width 8s steps(1) infinite, tw-03-blink 0.65s steps(2) infinite;
}
.tw-03__words {
display: flex;
flex-direction: column;
animation: tw-03-scroll 8s steps(4) infinite;
}
.tw-03__words span {
font-style: italic;
font-weight: 600;
color: var(--orange);
flex-shrink: 0;
height: 1.2em;
line-height: 1.2;
white-space: nowrap;
}
.tw-03__sub {
font-size: 1rem;
color: var(--muted);
letter-spacing: 0.05em;
}
@keyframes tw-03-scroll {
0% {
transform: translateY(0);
}
25% {
transform: translateY(-1.2em);
}
50% {
transform: translateY(-2.4em);
}
75% {
transform: translateY(-3.6em);
}
100% {
transform: translateY(0);
}
}
@keyframes tw-03-width {
0%,
100% {
width: 7.5ch;
}
25% {
width: 8ch;
}
50% {
width: 7.5ch;
}
75% {
width: 7.5ch;
}
}
@keyframes tw-03-blink {
0%,
100% {
border-color: var(--orange);
}
50% {
border-color: transparent;
}
}
@media (prefers-reduced-motion: reduce) {
.tw-03__slot {
animation: none;
border-right-color: var(--orange);
}
.tw-03__words {
animation: none;
}
}
```How this works
The rotating word lives inside a fixed-height overflow: hidden slot. A vertical stack of spans is translated upward via transform: translateY() in keyframe steps, creating the illusion of a new word rolling in from below. Simultaneously, the container's width keyframe expands and contracts between the ch values of each word so the highlight box snugly fits every word at the right moment.
The cursor blinks via a CSS border-right animation scoped to the container element. Because both animations share the same duration and loop infinitely, the timing stays locked: the word swap and the cursor blink stay perfectly phase-aligned without any JavaScript or timer synchronisation.
Make it yours
- Add more words by inserting additional
spanchildren and extending thetranslateYkeyframe steps — each word gets an equal time slice of100% / N. - Swap the highlight style from a solid background to an underline by removing
backgroundand addingborder-bottom: 3px solidon the container. - Adjust swap speed by changing the root animation duration — all child timings inherit from the parent loop variable via
calc().
Gotchas — read before shipping
- Words of very different lengths create jarring width jumps — keep your word list within a ±4 character range or use
min-widthto set a floor. - The vertical translateY approach will clip descenders on letters like g, p, y — add extra
line-heightorpadding-bottomto the inner spans. - Safari occasionally drops the first frame of the loop, causing a flash of the wrong word — add a tiny
animation-delay: 0.01sas a workaround.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 43+ | 9+ | 16+ | 43+ |
Pure transform + width animation — no cutting-edge features required.