Shimmering Text

PreviousNext

Smooth shimmering text animation built with Motion.

Docs
ncdaicomponent

Preview

Loading preview…
registry/shimmering-text/shimmering-text.tsx
"use client";

import type { HTMLMotionProps, Variants } from "motion/react";
import { motion } from "motion/react";
import * as React from "react";

import { cn } from "@/lib/utils";

export type ShimmeringTextProps = Omit<HTMLMotionProps<"span">, "children"> & {
  text: string;
  duration?: number;
  isStopped?: boolean;
};

export function ShimmeringText({
  text,
  duration = 1,
  isStopped = false,
  className,
  ...props
}: ShimmeringTextProps) {
  const createCharVariants = React.useCallback(
    (charIndex: number): Variants => ({
      running: {
        color: ["var(--color)", "var(--shimmering-color)", "var(--color)"],
        transition: {
          duration,
          repeat: Infinity,
          repeatType: "loop" as const,
          repeatDelay: text.length * 0.05,
          delay: (charIndex * duration) / text.length,
          ease: "easeInOut",
        },
      },
      stopped: {
        color: "var(--color)",
        transition: {
          duration: duration * 0.5,
          ease: "easeOut",
        },
      },
    }),
    [duration, text.length]
  );

  return (
    <motion.span
      className={cn(
        "inline-block select-none",
        "[--color:var(--color-zinc-400)] [--shimmering-color:var(--color-zinc-950)]",
        "dark:[--color:var(--color-zinc-600)] dark:[--shimmering-color:var(--color-zinc-50)]",
        className
      )}
      {...props}
    >
      {text?.split("")?.map((char, i) => (
        <motion.span
          key={i}
          className="inline-block whitespace-pre"
          initial="stopped"
          animate={isStopped ? "stopped" : "running"}
          variants={createCharVariants(i)}
        >
          {char}
        </motion.span>
      ))}
    </motion.span>
  );
}

Installation

npx shadcn@latest add @ncdai/shimmering-text

Usage

import { ShimmeringText } from "@/components/shimmering-text"
<ShimmeringText />