Intent Driven Content Reveal

Secondary content appears only when a reader pause suggests real interest.

This experiment requires full-page rendering.

Open live demo

HTML

<div class="intent-driven-content-reveal" data-intent-reveal>
  <aside class="intent-driven-content-reveal__rail">
    <p class="intent-driven-content-reveal__eyebrow">Reading intent</p>
    <h2>Intent Driven Content Reveal</h2>
    <p class="intent-driven-content-reveal__status" data-intent-status>
      Pause on a section to reveal the supporting insight.
    </p>

    <article class="intent-card" data-intent-card="signal">
      <p class="intent-card__eyebrow">Insight 01</p>
      <h3>Progressively reveal context</h3>
      <p>
        Secondary material waits until the reader slows down, which keeps the layout quieter during fast scanning.
      </p>
    </article>

    <article class="intent-card" data-intent-card="evidence">
      <p class="intent-card__eyebrow">Insight 02</p>
      <h3>Keep the article in front</h3>
      <p>
        The support layer appears beside the text, but never takes ownership of the page or interrupts the narrative.
      </p>
    </article>

    <article class="intent-card" data-intent-card="reflection">
      <p class="intent-card__eyebrow">Insight 03</p>
      <h3>Reward commitment, not motion</h3>
      <p>
        The reveal is tied to dwell and attention, not to generic scroll depth alone.
      </p>
    </article>
  </aside>

  <article class="intent-driven-content-reveal__article">
    <section
      class="intent-section"
      data-intent-section="signal"
      data-intent-label="Opening signal">
      <p class="intent-section__eyebrow">Section 01</p>
      <h3>Opening signal</h3>
      <p>
        A thoughtful editorial layout does not need to surface every supporting module immediately. It can first give the
        reader a stable place to begin.
      </p>
      <p>
        Only when the reader pauses near a section does the interface infer that more depth may be useful right now.
      </p>
    </section>

    <section
      class="intent-section"
      data-intent-section="evidence"
      data-intent-label="Evidence block">
      <p class="intent-section__eyebrow">Section 02</p>
      <h3>Evidence block</h3>
      <p>
        This behavior is especially useful for insight cards, source notes, side commentary and editorial marginalia.
      </p>
      <p>
        The reveal remains quiet, but it arrives at exactly the moment the reader is most likely to value the extra layer.
      </p>
    </section>

    <section
      class="intent-section"
      data-intent-section="reflection"
      data-intent-label="Reflection point">
      <p class="intent-section__eyebrow">Section 03</p>
      <h3>Reflection point</h3>
      <p>
        By responding to reading intent instead of blanket visibility rules, the design feels more considered and less
        promotional.
      </p>
      <p>
        The page stays content-first, while still making room for richer interpretation when the user invites it.
      </p>
    </section>
  </article>
</div>

CSS

.intent-driven-content-reveal {
  display: grid;
  gap: 22px;
  max-width: 1100px;
  margin: 0 auto;
}

.intent-driven-content-reveal__rail {
  align-self: start;
  padding: 26px;
  border-radius: 28px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  background:
    linear-gradient(180deg, rgba(19, 190, 156, 0.16), transparent 40%),
    rgba(10, 11, 14, 0.95);
}

.intent-driven-content-reveal__eyebrow,
.intent-section__eyebrow,
.intent-card__eyebrow {
  margin: 0 0 10px;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: rgba(255, 255, 255, 0.58);
}

.intent-driven-content-reveal__rail h2 {
  margin: 0 0 12px;
  font-size: clamp(2rem, 4vw, 3rem);
  line-height: 0.98;
}

.intent-driven-content-reveal__status {
  margin: 0 0 20px;
  color: rgba(255, 255, 255, 0.72);
  line-height: 1.7;
}

.intent-card {
  opacity: 0.16;
  transform: translateY(8px);
  filter: blur(10px);
  padding: 18px 20px;
  border-radius: 20px;
  border: 1px solid rgba(255, 255, 255, 0.06);
  background: rgba(255, 255, 255, 0.03);
  transition: opacity 240ms ease, transform 240ms ease, filter 240ms ease, border-color 240ms ease;
}

.intent-card + .intent-card {
  margin-top: 12px;
}

.intent-card.is-visible {
  opacity: 1;
  transform: translateY(0);
  filter: blur(0);
  border-color: rgba(19, 190, 156, 0.34);
}

.intent-card h3 {
  margin: 0 0 10px;
  color: #13be9c;
}

.intent-card p:last-child {
  margin: 0;
  color: rgba(255, 255, 255, 0.8);
  line-height: 1.7;
}

.intent-driven-content-reveal__article {
  display: grid;
  gap: 18px;
}

.intent-section {
  min-height: 66vh;
  padding: 30px;
  border-radius: 28px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.05), transparent 52%),
    rgba(8, 9, 11, 0.95);
}

.intent-section.is-active {
  border-color: rgba(250, 175, 59, 0.34);
}

.intent-section h3 {
  margin: 0 0 14px;
  max-width: 16ch;
  font-size: clamp(2rem, 4vw, 3.1rem);
  line-height: 0.98;
}

.intent-section p {
  max-width: 58ch;
  margin: 0;
  color: rgba(255, 255, 255, 0.84);
  line-height: 1.78;
}

.intent-section p + p {
  margin-top: 14px;
}

@media only screen and (min-width: 980px) {
  .intent-driven-content-reveal {
    grid-template-columns: 340px minmax(0, 1fr);
    align-items: start;
  }

  .intent-driven-content-reveal__rail {
    position: sticky;
    top: 18px;
  }
}

JavaScript

(function () {
  const root = document.querySelector('[data-intent-reveal]');
  if (!root) return;

  const status = root.querySelector('[data-intent-status]');
  const sections = Array.from(root.querySelectorAll('[data-intent-section]'));
  const cards = Array.from(root.querySelectorAll('[data-intent-card]'));
  if (!status || !sections.length || !cards.length) return;

  let activeId = sections[0].dataset.intentSection;
  let revealTimer = null;

  function syncActiveSection(id) {
    activeId = id;

    sections.forEach(section => {
      section.classList.toggle('is-active', section.dataset.intentSection === id);
    });
  }

  function revealCard(id) {
    const activeSection = sections.find(section => section.dataset.intentSection === id);
    const label = activeSection ? activeSection.dataset.intentLabel : 'this section';

    cards.forEach(card => {
      card.classList.toggle('is-visible', card.dataset.intentCard === id);
    });

    status.textContent = `${label} unlocked after the reader paused long enough to signal attention.`;
  }

  function queueReveal() {
    clearTimeout(revealTimer);
    status.textContent = 'Hold your place for a moment to reveal the supporting insight.';
    revealTimer = setTimeout(() => revealCard(activeId), 650);
  }

  const observer = new IntersectionObserver(
    entries => {
      let nextSection = null;
      let highestRatio = 0;

      entries.forEach(entry => {
        if (entry.intersectionRatio > highestRatio) {
          highestRatio = entry.intersectionRatio;
          nextSection = entry.target.dataset.intentSection;
        }
      });

      if (nextSection) {
        syncActiveSection(nextSection);
        queueReveal();
      }
    },
    {
      threshold: [0.25, 0.45, 0.65]
    }
  );

  sections.forEach(section => observer.observe(section));
  window.addEventListener('scroll', queueReveal, { passive: true });
  queueReveal();
})();
  • Tech used Vanilla JS, WordPress-ready, No dependencies
  • Integration level Advanced (custom logic)
  • Performance safe Yes

What it solves

Prevents insight blocks and supporting context from competing with the main article before the reader is ready for them.

Intent Driven Content Reveal keeps callouts and insight layers out of the way until a reader slows down enough to suggest genuine attention. Instead of assuming that every visible module deserves immediate space, the pattern waits for dwell and focus before it responds.

This makes secondary material feel supportive rather than promotional, especially in long-form editorial experiences where interruption can erode trust.