Components / Motion / Tracing Beam

Tracing Beam beta

A line of light that travels down the page as you read, filling the rail beside the text.

Preview

The top

Every long page makes the same promise at the top: this will be worth it. The beam starts empty because the reader has not yet decided.

The middle

Halfway down, most readers are skimming for the part that matters to them. A filled rail says the end is a known distance away, which is often enough to keep them reading carefully instead.

The turn

Somewhere in the third quarter the page has to pay off its opening promise. Structure helps: short sections, honest headings, and nothing that exists only to make the page longer.

The end

When the dot reaches the bottom, the reader has the whole argument. What they do next — copy a part, open the registry, close the tab — was decided by the words, but the beam walked them there.

<div class="k-beam" data-beam>
  <div class="k-beam-rail" aria-hidden="true"><div class="k-beam-fill"></div><div class="k-beam-dot"></div></div>
  <div class="k-beam-body">
    <section><h4>The top</h4><p>Every long page makes the same promise at the top: this will be worth it. The beam starts empty because the reader has not yet decided.</p></section>
    <section><h4>The middle</h4><p>Halfway down, most readers are skimming for the part that matters to them. A filled rail says the end is a known distance away, which is often enough to keep them reading carefully instead.</p></section>
    <section><h4>The turn</h4><p>Somewhere in the third quarter the page has to pay off its opening promise. Structure helps: short sections, honest headings, and nothing that exists only to make the page longer.</p></section>
    <section><h4>The end</h4><p>When the dot reaches the bottom, the reader has the whole argument. What they do next — copy a part, open the registry, close the tab — was decided by the words, but the beam walked them there.</p></section>
  </div>
</div>
/* KATA Tracing Beam — the rail fills as the reader travels. */
.k-beam{display:grid;grid-template-columns:16px 1fr;gap:16px;font-family:var(--k-font);color:var(--k-ink)}
.k-beam-rail{position:relative}
.k-beam-rail::before{content:"";position:absolute;left:7px;top:4px;bottom:4px;width:2px;background:var(--k-line);border-radius:2px}
.k-beam-fill{position:absolute;left:7px;top:4px;width:2px;height:0;background:var(--k-accent);border-radius:2px}
.k-beam-dot{position:absolute;left:3px;top:4px;width:10px;height:10px;border-radius:50%;background:var(--k-accent);box-shadow:0 0 0 4px var(--k-accent-bg)}
.k-beam-body{height:264px;overflow:auto;padding-inline-end:6px}
.k-beam-body section{margin-bottom:20px}
.k-beam-body h4{font-size:14px;font-weight:600;margin-bottom:5px}
.k-beam-body p{font-size:13px;line-height:1.8;color:var(--k-ink-2)}
// KATA Tracing Beam — fill height is the scroll fraction, kept honest.
document.querySelectorAll('[data-beam]').forEach(function (root) {
  var body = root.querySelector('.k-beam-body');
  var rail = root.querySelector('.k-beam-rail');
  var fill = root.querySelector('.k-beam-fill');
  var dot = root.querySelector('.k-beam-dot');
  function update() {
    var max = body.scrollHeight - body.clientHeight;
    var f = max > 0 ? body.scrollTop / max : 0;
    var h = (rail.clientHeight - 8) * f;
    fill.style.height = h + 'px';
    dot.style.top = (4 + h) + 'px';
  }
  body.addEventListener('scroll', update, { passive: true });
  update();
});

Installation

CLI

node kata-ui.mjs add tracing-beam

Writes the part’s CSS and JS into your project. New to the CLI? See the CLI doc.

Manual

  1. Load tokens.css once, before any part.
  2. Copy the CSS tab into your stylesheet.
  3. Copy the HTML where it belongs. The part has a script — include it after the markup; it initializes itself.

Usage

For long reads — guides, changelogs, case studies — where knowing how far in you are is kindness. The fill is the scroll fraction of the container beside it, nothing more mystical. Pair it with a Scrollspy when the reader also needs to jump; use it alone when they only need to feel progress.

Accessibility

The beam is a progress picture, aria-hidden, duplicating what the scrollbar already says. Content never depends on it, and under prefers-reduced-motion the rail stays a plain hairline.

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-beamclass
.k-beam-railclass
.k-beam-fillclass
.k-beam-dotclass
.k-beam-bodyclass
data-beamdata hook
aria-hiddenARIA

Related parts