webdevpuneet.com

Typed.js Rotating Headline — Hero Typewriter Snippet

Typed.js Rotating Headline · Heroes · Plain HTML, CSS & JS · Live preview

CategoryHeroes

Copy & paste

Source Code

Requires
<section class="trh-hero">
  <div class="trh-inner">
    <span class="trh-pill">typed.js · smart backspace</span>

    <h1 class="trh-title">
      We build
      <span class="trh-typed"><span id="trhTarget"></span></span>
    </h1>

    <p class="trh-caption" id="trhCaption">Component libraries that survive a rebrand.</p>

    <div class="trh-actions">
      <button class="trh-cta">Book a call</button>
      <button class="trh-ghost" id="trhToggle">Pause</button>
    </div>

    <div class="trh-speeds" id="trhSpeeds">
      <button class="trh-chip" data-speed="90">Slow</button>
      <button class="trh-chip is-on" data-speed="55">Normal</button>
      <button class="trh-chip" data-speed="22">Fast</button>
    </div>
  </div>
</section>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Smart backspace
Rewinds only to where consecutive strings diverge.
Index-synced UI
preStringTyped drives accent color and caption per line.
One variable, five elements
A single --accent custom property retints the whole hero.
Cross-faded captions
Opacity out, text swap, opacity in — no mid-line flicker.
Reflow-safe headline
The rotating phrase is display:block so static text never rewraps.
Derived backspace speed
Deleting runs at 55% of type speed so rotations never drag.
Terminal-accurate cursor
A hard-edged blink keyframe on the injected .typed-cursor.
WCAG pause control
stop() and start() satisfy the pause requirement for looping motion.

About this UI Snippet

Typed.js Rotating Headline — Typewriter Text That Drives the Whole Hero

Screenshot of the Typed.js Rotating Headline snippet rendered live

A rotating headline is the most common hero pattern on the web and one of the easiest to do badly. The version that hurts conversion types one character at a time forever, jumps the layout on every wrap, and leaves screen readers reading a stream of half-words. This snippet fixes each of those and adds the thing most implementations miss entirely: the rest of the hero reacts to which line is being typed.

Smart backspace, the feature worth the dependency

You could write a typewriter in thirty lines. The reason to reach for Typed.js is smartBackspace, and it is genuinely hard to reimplement well:

smartBackspace: true

With it off, every rotation deletes the entire line character by character and retypes the next one from nothing. With it on, Typed.js diffs consecutive strings and rewinds only to the point where they differ. The first two strings here are chosen to demonstrate it exactly:

- design systems that scale. - design systems that ship on Friday.

The shared prefix "design systems that " is never deleted. The line rewinds to that point and continues, which is both dramatically faster and reads as an idea being *revised* rather than erased. Writing your rotating strings to share prefixes is a copywriting decision that this one option turns into a visual one.

Syncing the rest of the hero

The preStringTyped callback fires with the array index of the string about to be typed, before typing starts — which makes it the right hook for changing anything that should already be correct when the new line begins:

preStringTyped: applyMeta

applyMeta(i) writes a new accent color to a CSS custom property on the hero root (hero.style.setProperty('--accent', m.accent)) and swaps the caption underneath. Because --accent is consumed by the pill, the typed text, the CTA background, and the active chip border, one property assignment retints five elements, each with its own CSS transition so they ease rather than snap.

The caption swap is handled with a two-step fade rather than a hard text replacement: a .fade class drops opacity, the text is replaced 220ms later inside a setTimeout, then the class is removed. Replacing the text instantly while the line is still visible produces a jarring flicker that undercuts the smoothness of everything else.

Layout stability

.trh-typed { display: block } puts the rotating phrase on its own line. This is deliberate: an inline rotating span changes the width of the headline on every character, which can rewrap the static text before it and cause visible reflow on every keystroke. Giving it a dedicated line means only that line's width changes.

.trh-caption { min-height: 24px } reserves the caption's space so a shorter line does not collapse the block and shift the buttons upward.

The cursor

Typed.js injects its own .typed-cursor element, which is why the CSS styles a class it never declares in the HTML. The default blink is a simple opacity toggle; the trhBlink keyframe here holds the cursor solid for 45% of the cycle and hidden for 45% with sharp transitions, which matches how a real terminal cursor behaves far better than a smooth fade. cursorChar: '▌' swaps the default pipe for a block character that reads better at display sizes.

Rebuilding for speed changes

Typed.js reads typeSpeed once at construction, so changing speed means a new instance — and if (typed) typed.destroy() must come first. Without it, the old instance keeps its interval running and writes to the same element, so two typewriters fight over one span and produce interleaved garbage. destroy() clears the timers and removes the injected cursor.

Note that backSpeed is derived rather than fixed: Math.max(10, Math.round(speed * 0.55)). Deleting should always feel faster than typing — a rotation that erases at the same speed it writes feels twice as slow as it is.

Pause, and why it matters

The pause button calls typed.stop() and typed.start(). This is not decoration: WCAG 2.2.2 requires that any automatically moving content lasting more than five seconds can be paused. A permanently looping headline qualifies, so shipping one without a pause control is an accessibility failure, not a missing nice-to-have.

Reusing it

Rewrite STRINGS and the matching META array — keep them the same length, since applyMeta indexes straight into it. Write your strings to share leading words wherever the meaning allows, so smartBackspace has something to work with. For a static alternative without the dependency, see typewriter, or word flip hero when you want whole words to swap rather than type.

Step by step

How to Use

  1. 1
    Add the Typed.js CDNInclude the typed.umd build from the CDN panel — global Typed.
  2. 2
    Paste HTML, CSS, and JSThe headline starts rotating through five value propositions.
  3. 3
    Watch the rewindLines sharing a prefix rewind only to the difference, not to empty.
  4. 4
    Notice the hero retintAccent color and caption change with each new line.
  5. 5
    Change the speedSlow, Normal, and Fast rebuild the instance with a derived backspace speed.
  6. 6
    Write your own linesEdit STRINGS and META together — they are indexed in parallel.

Real-world uses

Common Use Cases

Agency and SaaS heroes
Rotate through what you actually sell, with smart backspace rewinding only to where consecutive strings diverge.
Portfolio landings
Cycle roles or disciplines, with a single --accent custom property retinting five elements as each line changes.
Feature carousel pairings
Pair with a word flip hero for a quieter variation, using cross-faded captions without mid-line flicker.
Waitlist and launch pages
Type the benefit above a waitlist signup, with preStringTyped keeping accent colour and caption in step with the line.
Hiring and typewriter learning
Rotate the roles you are hiring for, and study how to avoid layout jumps and screen reader noise that make rotating headlines hurt conversion.
Related: Hero with Terminal Boot Sequence
See the Hero with Terminal Boot Sequence for a related heroes pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

It diffs the current string against the next one and rewinds only to the point where they differ, instead of deleting the whole line. With strings like "design systems that scale." followed by "design systems that ship on Friday.", the shared prefix is never erased — the rotation is faster and reads as a revision rather than a restart.

The preStringTyped callback receives the index of the string about to be typed. It writes the matching accent color to a --accent custom property on the hero root, and because the pill, typed text, CTA background, and active chip border all consume that variable, one assignment retints five elements — each easing via its own CSS transition.

An inline rotating span changes the headline width on every character, which can rewrap the static text before it and cause visible reflow on each keystroke. Setting the typed span to display: block confines width changes to that line alone.

Typed.js reads typeSpeed once at construction, so a speed change needs a new instance. destroy() must be called first — otherwise the old instance keeps its timers running against the same element and two typewriters interleave characters into one span.

Deleting should always feel quicker than writing; a rotation that erases at the same rate it types feels about twice as slow as it is. Deriving it as roughly 55% of the type speed, floored at 10ms, keeps that ratio correct at every speed setting.

Create the Typed instance in a mount effect against a ref to the target span, and call destroy() in cleanup so a remount does not leave a running timer writing into a detached node. Hold the accent and caption in state and set them from the preStringTyped callback rather than mutating the DOM. Rebuild the instance in an effect keyed to the speed value.