A restrained highlight that travels across text and stops with reduced motion.
A quiet moment of anticipation.
pnpm dlx shadcn@latest add @latheui/text-shimmerFirst time? Run npx latheui init once to add the @latheui registry. The CLI then writes the source into your project and installs what it needs. Or add it by hand:
Install the npm dependencies.
pnpm add motionAdd the Lathe items this component imports.
lib/motion.tsCopy the source into your project.
"use client"
import * as React from "react"
import { motion } from "motion/react"
import { cn } from "@/lib/utils"
import { useMotionSafe } from "@/lib/motion"
export type TextShimmerProps = {
children: string
duration?: number
className?: string
}
export function TextShimmer({
children,
duration = 2.5,
className,
}: TextShimmerProps) {
const { reduced } = useMotionSafe()
return (
<motion.span
className={cn("inline-block", className)}
style={
reduced
? undefined
: {
backgroundImage:
"linear-gradient(110deg, var(--muted-foreground) 35%, var(--foreground) 50%, var(--muted-foreground) 65%)",
backgroundSize: "250% 100%",
backgroundClip: "text",
color: "transparent",
}
}
animate={
reduced ? undefined : { backgroundPosition: ["150% 0%", "-150% 0%"] }
}
transition={{
duration: Math.max(0.2, duration),
repeat: Infinity,
ease: "linear",
}}
>
{children}
</motion.span>
)
}Depends on
| Prop | Type | Default | Description |
|---|---|---|---|
| children* (required) | string | — | Readable text content. |
| duration | number | 2.5 | Seconds per highlight cycle. |
| className | string | — | Typography and spacing. |
Combine the control with your own layout. Semantic colors follow the active theme.
import { TextShimmer } from "@/components/ui/text-shimmer"
export default function Demo(){return <div className="space-y-2 text-center"><TextShimmer className="text-xl font-medium">Making room for your next idea</TextShimmer><p className="text-xs text-muted-foreground">A quiet moment of anticipation.</p></div>}