tween
ComponentsTemplatesShowcaseContact

Command Palette

Search for a command to run...

Getting Started
  • Introduction
  • Installation
  • StoryNew
Guides
  • Motion Principles
  • Scroll and Smooth Scroll
  • Performance and Accessibility
Scroll Animations
  • Sticky Cards Scroll
  • Rise Fan Cards Scroll
  • Rotate Stack Scroll
  • Doodle Lens ScrollNew
  • Slit Open Hero ScrollNew
  • Logo Mask Zoom ScrollNew
  • ASCII Dissolve ScrollNew
  • Lottie Flight ScrollNew
  • Inline Icon Text ScrollNew
  • Starfield ScrollNew
  • Name Swap ScrollNew
  • Spotlight Gallery HeroNew
  • Slit Rotate Hero ScrollNew
  • Stroke Cover ScrollNew
  • Stroke Rows ScrollNew
Text Animations
  • Text Skew Reveal
  • Block Text Reveal
Hover & Cursor
  • Image Trail Cursor
  • Cursor Depth Logo
  • Physics Tag Drop
  • Elastic Card ListNew
  • Magnetic Cards SpringNew
Sliders & Carousels
  • Wheel Fullscreen Carousel
  • Ripple Displacement Slider
  • Three.js Blend Slider
  • Stacked Deck Slider
  • Orbit Cylinder SliderNew
  • Fan Stack SliderNew
  • Exponential Strip SliderNew
  • Dual Column SliderNew
Galleries & Grids
  • Scroll Wave Gallery
Menus & Navigation
  • Shrink Page MenuNew
Preloaders & Intros
  • Floating Items RevealNew
  • Word Cycle RevealNew
  • Tile Grid LoaderNew
Page Transitions
  • Panel Assembly TransitionNew
3D & WebGL
  • Fractal Glass Hero
  • Fluid Cursor Canvas
  • Fluid Portrait Hero
  • Fluid Gradient Canvas
  • Inversion Lens HoverNew
UI Elements
  • Circular Widgets
  • Vinyl Cover
  • Image Explosion Footer
  • Accordion Image FramesNew

(Tween) — Motion registry

Animated components & full sites, one command away.

Product

  • Components
  • Templates
  • Installation
  • Guides
  • Blog
  • Contact

Categories

  • Scroll Animations
  • Text Animations
  • Hover & Cursor
  • Sliders & Carousels
  • Galleries & Grids
  • Menus & Navigation
  • Preloaders & Intros
  • Page Transitions
  • 3D & WebGL
  • UI Elements
TWEEN
ease: power2.inOut0.00s
© 2026 TweenBack to topBuilt by mohammad
  1. Docs/
  2. Components/
  3. Block Text Reveal

Block Text Reveal

PreviousNext

A line-by-line text reveal where a colored block wipes across each line before lifting it into view with a stagger.

Open in
block-text-reveal-demo

Ferrous — Issue 07, Autumn

Heavy type, set loose

Notes from the composing room floor

§ 02 / On Weight

We set every headline twice: once to be read, once to be felt. The second pass is slower and heavier, and it is the one our readers remember.

— Field Note 14

A page should open like a shutter, one line at a time, never all at once.

Set in Lead · Printed in Ghent

Print it
like it matters

Type · Press · Archive

Ferrous

components/ui/block-text-reveal-demo.tsx
import { BlockTextReveal } from "@/registry/tween/block-text-reveal"

const INK = "#0b0b0c"
const CREAM = "#f1ece1"
const WINE = "#b8121b"
const BONE = "#e8e2d3"
const NIGHT = "#111418"

const sectionBase =
  "@container/block relative flex w-full flex-col overflow-hidden"
const minPreview = { minHeight: "var(--preview-h, 100vh)" }

export function BlockTextRevealDemo() {
  return (
    <div className="w-full" style={{ backgroundColor: CREAM, color: INK }}>
      <section
        className={`${sectionBase} items-center justify-center px-6 py-24 text-center`}
        style={{ ...minPreview, backgroundColor: CREAM }}
      >
        <BlockTextReveal blockColor={INK}>
          <p className="mb-8 text-[clamp(0.7rem,1.4cqi,0.95rem)] font-medium tracking-[0.35em] uppercase opacity-80">
            Ferrous — Issue 07, Autumn
          </p>
        </BlockTextReveal>

        <BlockTextReveal blockColor={WINE} stagger={0.1}>
          <h1
            className="w-[min(92%,18ch)] text-center text-[clamp(2.5rem,12cqi,9rem)] leading-[0.95] font-black [letter-spacing:-0.04em] uppercase"
            style={{ color: WINE }}
          >
            Heavy type, set loose
          </h1>
        </BlockTextReveal>

        <BlockTextReveal blockColor={INK}>
          <p className="mt-10 w-[min(80%,42ch)] text-center text-[clamp(0.9rem,1.6cqi,1.05rem)] font-medium tracking-[0.2em] uppercase opacity-70">
            Notes from the composing room floor
          </p>
        </BlockTextReveal>
      </section>

      <section
        className={`${sectionBase} items-start justify-center px-8 py-24 md:px-16`}
        style={{ ...minPreview, backgroundColor: BONE }}
      >
        <div className="grid w-full grid-cols-1 gap-12 md:grid-cols-[1fr_3fr]">
          <BlockTextReveal blockColor={WINE}>
            <p
              className="text-[clamp(1rem,1.8cqi,1.25rem)] font-semibold tracking-[0.25em] uppercase"
              style={{ color: WINE }}
            >
              § 02 / On Weight
            </p>
          </BlockTextReveal>

          <BlockTextReveal blockColor={INK} stagger={0.13}>
            <p className="w-[min(100%,40ch)] text-left text-[clamp(1.5rem,4.2cqi,3rem)] leading-[1.15] font-medium [letter-spacing:-0.015em]">
              We set every headline twice: once to be read, once to be felt. The
              second pass is slower and heavier, and it is the one our readers
              remember.
            </p>
          </BlockTextReveal>
        </div>
      </section>

      <section
        className={`${sectionBase} items-center justify-center px-6 py-24 text-center`}
        style={{ ...minPreview, backgroundColor: NIGHT, color: CREAM }}
      >
        <BlockTextReveal blockColor={WINE}>
          <p
            className="mb-10 text-[clamp(0.7rem,1.4cqi,0.95rem)] font-medium tracking-[0.4em] uppercase"
            style={{ color: WINE }}
          >
            — Field Note 14
          </p>
        </BlockTextReveal>

        <BlockTextReveal blockColor={CREAM} alternate stagger={0.14}>
          <h2
            className="w-[min(92%,22ch)] text-center text-[clamp(1.75rem,6.2cqi,4.5rem)] leading-[1.05] font-medium [letter-spacing:-0.025em]"
            style={{ color: CREAM }}
          >
            A page should open like a shutter, one line at a time, never all at
            once.
          </h2>
        </BlockTextReveal>

        <div className="mt-12 flex items-center gap-4 opacity-70">
          <span className="h-px w-12" style={{ backgroundColor: CREAM }} />
          <BlockTextReveal blockColor={CREAM}>
            <p
              className="text-[clamp(0.7rem,1.3cqi,0.85rem)] font-medium tracking-[0.3em] uppercase"
              style={{ color: CREAM }}
            >
              Set in Lead · Printed in Ghent
            </p>
          </BlockTextReveal>
          <span className="h-px w-12" style={{ backgroundColor: CREAM }} />
        </div>
      </section>

      <section
        className={`${sectionBase} items-center justify-center px-6 py-24 text-center`}
        style={{ ...minPreview, backgroundColor: CREAM }}
      >
        <BlockTextReveal blockColor={WINE} stagger={0.11}>
          <h1
            className="w-[min(92%,20ch)] text-center text-[clamp(2.25rem,11cqi,8rem)] leading-[0.92] font-black [letter-spacing:-0.045em] uppercase"
            style={{ color: WINE }}
          >
            Print it
            <br />
            like it matters
          </h1>
        </BlockTextReveal>

        <div className="mt-12 flex w-[min(90%,60ch)] flex-col items-center gap-2">
          <BlockTextReveal blockColor={INK}>
            <p className="text-[clamp(0.8rem,1.4cqi,0.95rem)] font-medium tracking-[0.3em] uppercase opacity-70">
              Type · Press · Archive
            </p>
          </BlockTextReveal>
          <BlockTextReveal blockColor={INK}>
            <p className="text-[clamp(0.75rem,1.2cqi,0.85rem)] font-medium tracking-[0.5em] uppercase opacity-50">
              Ferrous
            </p>
          </BlockTextReveal>
        </div>
      </section>
    </div>
  )
}

Installation

pnpm dlx shadcn@latest add https://tweenui.dev/r/block-text-reveal.json

Usage

import { BlockTextReveal } from "@/components/ui/block-text-reveal"
<BlockTextReveal blockColor="#b8121b">
  <h1>Motion is part of the message.</h1>
</BlockTextReveal>
 
<BlockTextReveal blockColor="#000" alternate>
  <p>Every line is masked, wiped, and lifted into place.</p>
</BlockTextReveal>
 
<BlockTextReveal blockColor="#000" animateOnScroll={false}>
  <p>Play the reveal immediately on mount.</p>
</BlockTextReveal>

The child is split into lines, and each line gets its own block overlay. The block first wipes in to fully cover the line, then wipes back out to expose the text, which simultaneously lifts up by lineLift pixels. Lines fire in sequence with stagger, so the paragraph assembles top to bottom. Set alternate to flip every other line's wipe direction for a woven effect, or disable animateOnScroll to run the whole sequence as soon as the component mounts.

Props

PropTypeDefaultDescription
childrenReactNode—Single text element (or wrapper) to animate.
animateOnScrollbooleantrueTrigger the reveal on scroll-into-view. false plays immediately.
delaynumber0Delay (seconds) before the first line starts.
blockColorstring"var(--foreground)"CSS color for the wiping block.
staggernumber0.07Per-line stagger (seconds).
durationnumber0.42Base tween budget (seconds). Cover, reveal, and lift durations derive from this.
easestring"power4.in"Easing for the wipe-in (cover phase).
easeOutstring"expo.out"Easing for the wipe-out (reveal phase) and the line lift.
lineLiftnumber10How far each line lifts (px) as it becomes visible. Set 0 to disable.
alternatebooleanfalseIf true, alternate lines wipe in from the right instead of the left.
startstring"top 90%"ScrollTrigger start value when animateOnScroll is true.
scrollerHTMLElement | string | null—Optional ScrollTrigger scroller; defaults to the ambient preview scroller.
classNamestring—Merged onto the cloned child element.
Text Skew RevealImage Trail Cursor

On This Page

InstallationUsageProps

Contribute

  • Report an issue
  • Request a feature
  • Edit this page