This component no longer exists. It was in blaze-motion’s manifest when we first indexed it and is not there now — the registry served its inventory on 2026-08-06 and this item was not on it. The install command below will fail. It is kept here because a tutorial somewhere still tells people to run it.
Text Reveal
blaze-motion/text-revealRemovedComponent
Word-by-word text reveal — tokens rise and fade in sequence as the line enters view.
Install it
npx shadcn@latest add https://motion.asmitsah.dev/r/text-reveal.jsonSource
1"use client";23import * as m from "motion/react-m";4import {5 type CSSProperties,6 Fragment,7 isValidElement,8 type ReactElement,9 type ReactNode,10} from "react";11import { feel, textRevealContainer, textRevealItem, viewportOnce } from "@/lib/motion";1213const TAGS = {14 span: m.span,15 div: m.div,16 p: m.p,17 h1: m.h1,18 h2: m.h2,19 h3: m.h3,20 h4: m.h4,21 h5: m.h5,22 h6: m.h6,23} as const;2425type Tag = keyof typeof TAGS;26type HostProps = { className?: string; style?: CSSProperties; children?: ReactNode };2728type TextRevealProps = {29 /** A single host element (h1–h6 / p / span / div) whose own children is a30 * plain string. TextReveal reconstructs THAT element as the animated one —31 * its tag, className + style win; no extra DOM wrapper is added. */32 children: ReactNode;33 delay?: number;34 by?: "word" | "char";35 stagger?: number;36 trigger?: "inView" | "mount";37};3839export function TextReveal({40 children,41 delay = 0,42 by = "word",43 stagger,44 trigger = "inView",45}: TextRevealProps) {46 const step = stagger ?? (by === "char" ? feel.textStaggerChar : feel.textStagger);47 const play =48 trigger === "mount"49 ? ({ animate: "animate" } as const)50 : ({ whileInView: "animate", viewport: viewportOnce } as const);5152 // Read the wrapped element's tag + props + string text so we can re-render it53 // as the matching m[tag] carrying the stagger — the caller's tag/className win.54 const child = isValidElement(children) ? (children as ReactElement<HostProps>) : null;55 const tag = child && typeof child.type === "string" ? child.type : null;56 const text = child && typeof child.props.children === "string" ? child.props.children : null;5758 // Fail soft: if the child isn't a single host element wrapping a plain string,59 // render it untouched (unanimated) rather than crash.60 if (!child || !tag || !(tag in TAGS) || text === null) {61 return <>{children}</>;62 }6364 const Container = TAGS[tag as Tag] as typeof m.span;65 const { className, style } = child.props;66 const words = text.trim().split(/\s+/);67 // Headings permit an accessible name; generic tags (span/div/p) don't — so an68 // aria-label there is prohibited. role="img" lets the label name the composite69 // while the per-token spans stay aria-hidden (no char-by-char read).70 const isHeading = tag.length === 2 && tag.startsWith("h");7172 return (73 // aria-label carries the full string so SR reads it whole, not per-span.74 <Container75 className={className}76// … truncated
What it pulls in
npm packages
Other registry items
