Studio KitAdvanced Text Animationsmotion/react

BlurInText

Headline that resolves word by word from a soft blur, fading and lifting each word into focus with a configurable stagger and initial blur radius.

Preview

Customize

5 props
0.6
0.08
12

Installation

Copies the component source and its CSS Module into your project.

npx motionfoundry add blur-in-text

Writes components/ui/blur-in-text.tsx and components/styles/blur-in-text.module.css.

Usage

Updates live as you change the controls — only props that differ from the defaults are included.

example.tsx
1import { BlurInText } from "@motionfoundry/ui";2 3export function Example() {4  return (5    <BlurInText />6  );7}

Props

PropTypeDefault
text

Text revealed word by word.

string'Motion that feels considered, not decorated.'
duration

Per-word animation duration in seconds.

number0.6
stagger

Delay between consecutive words in seconds.

number0.08
blur

Initial blur radius in pixels.

number12
as

Semantic element to render.

'h1' | 'h2' | 'h3' | 'p''h2'
className

Additional class merged onto the root element.

string''

Accessibility

Renders a semantic h1/h2/h3/p carrying the full sentence in aria-label while the per-word spans are aria-hidden. Under prefers-reduced-motion words render in their final, unblurred state with no animation.

Toggle prefers-reduced-motion in your OS or browser devtools (Rendering → Emulate CSS media feature) to verify the reduced-motion state.

Source

components/ui/blur-in-text.tsx
1"use client";2 3import * as React from "react";4import { motion, useReducedMotion } from "motion/react";5import styles from "../styles/blur-in-text.module.css";6 7export interface BlurInTextProps {8  /** Text to reveal word by word */9  text?: string;10  /** Per-word animation duration in seconds */11  duration?: number;12  /** Delay between consecutive words in seconds */13  stagger?: number;14  /** Initial blur radius in pixels */15  blur?: number;16  /** Semantic element to render */17  as?: "h1" | "h2" | "h3" | "p";18  /** Optional className */19  className?: string;20}21 22export function BlurInText({23  text = "Motion that feels considered, not decorated.",24  duration = 0.6,25  stagger = 0.08,26  blur = 12,27  as = "h2",28  className = "",29}: BlurInTextProps) {30  const prefersReducedMotion = useReducedMotion();31  const words = text.split(" ").filter(Boolean);32  const Tag = as;33 34  return (35    <Tag aria-label={text} className={`${styles.root} ${className}`.trim()}>36      {words.map((word, i) => (37        <motion.span38          key={`${word}-${i}`}39          aria-hidden="true"40          className={styles.word}41          initial={prefersReducedMotion ? false : { opacity: 0, filter: `blur(${blur}px)`, y: 8 }}42          animate={{ opacity: 1, filter: "blur(0px)", y: 0 }}43          transition={{ duration, delay: i * stagger, ease: "easeOut" }}44        >45          {word}46          {i < words.length - 1 ? " " : null}47        </motion.span>48      ))}49    </Tag>50  );51}