GitHub

Components / Motion / Text reveal

Text reveal beta

A headline that arrives word by word, each word rising into place. Settles once, then stays.

Preview

Parts you copy. Code you own. Motion with a machined finish.

<p data-reveal style="color:var(--k-ink);font-size:clamp(22px,4vw,30px);font-weight:600;letter-spacing:-.02em;line-height:1.35;max-width:22em">Parts you copy. Code you own. Motion with a machined finish.</p>
/* KATA Text reveal */
.k-rv-w{display:inline-block;overflow:hidden;vertical-align:bottom;padding-bottom:.12em;margin-bottom:-.12em}
.k-rv-i{display:inline-block;transform:translateY(115%);transition:transform .7s cubic-bezier(.3,.7,.3,1);transition-delay:calc(var(--i,0)*45ms)}
[data-reveal].in .k-rv-i{transform:none}
@media (prefers-reduced-motion: reduce){.k-rv-i{transform:none;transition:none}}
// KATA Text reveal — split into words, rise once when visible.
document.querySelectorAll('[data-reveal]').forEach(function (el) {
  var words = el.textContent.trim().split(/\s+/);
  el.setAttribute('aria-label', el.textContent.trim());
  el.textContent = '';
  words.forEach(function (w, i) {
    var outer = document.createElement('span');
    outer.className = 'k-rv-w';
    outer.setAttribute('aria-hidden', 'true');
    var inner = document.createElement('span');
    inner.className = 'k-rv-i';
    inner.style.setProperty('--i', i);
    inner.textContent = w;
    outer.appendChild(inner);
    el.appendChild(outer);
    el.appendChild(document.createTextNode(' '));
  });
  if (!('IntersectionObserver' in window) || window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
    el.classList.add('in');
    return;
  }
  var io = new IntersectionObserver(function (entries) {
    if (entries[0].isIntersecting) {
      el.classList.add('in');
      io.disconnect();
    }
  }, { threshold: 0.35 });
  io.observe(el);
});

Usage

For one headline per page — the hero, a section opening. The script splits the text into words; the stagger is 45ms per word and the whole thing runs once.

Accessibility

Without the script, the text is simply text. Screen readers read the original sentence; reduced-motion users get it static.