Shiny Text

A premium Apple-style shine effect that sweeps across text like light reflecting off a glossy surface. Features a bright metallic base with multiple shine layers and glow effect.

Premium Shine

Continuous bright shine animation with glow effect - like Apple product text.

Hover Trigger

Golden shine activates when user hovers over the text.

Vision Pro Style

Extra wide shine with slow animation for maximum impact.

Installation

npm install framer-motion
pnpm install framer-motion
yarn add framer-motion
bun add framer-motion

Copy and paste the following code into your project.

'use client';import { useEffect, useRef, useState, useMemo } from 'react';import { motion, useInView } from 'framer-motion';interface ShinyTextProps {  text: string;  className?: string;  shineColor?: string;  duration?: number;  angle?: number;  shimmerWidth?: number;  trigger?: 'hover' | 'loop' | 'inView';  disabled?: boolean;}export const ShinyText = ({  text,  className = '',  shineColor = 'rgba(255, 255, 255, 1)',  duration = 3,  angle = 120,  shimmerWidth = 200,  trigger = 'loop',  disabled = false,}: Readonly<ShinyTextProps>) => {  const containerRef = useRef<HTMLSpanElement>(null);  const isInView = useInView(containerRef, { once: false, amount: 0.5 });  const [isHovering, setIsHovering] = useState(false);  const [shouldAnimate, setShouldAnimate] = useState(false);  // Check for reduced motion preference  const prefersReducedMotion =    typeof window !== 'undefined' &&    window.matchMedia('(prefers-reduced-motion: reduce)').matches;  useEffect(() => {    if (disabled || prefersReducedMotion) {      setShouldAnimate(false);      return;    }    switch (trigger) {      case 'loop':        setShouldAnimate(true);        break;      case 'inView':        setShouldAnimate(isInView);        break;      case 'hover':        setShouldAnimate(isHovering);        break;    }  }, [trigger, isInView, isHovering, disabled, prefersReducedMotion]);  // Enhanced shimmer gradient with brighter, wider shine  const shimmerGradient = useMemo(    () => `linear-gradient(    ${angle}deg,    transparent 0%,    transparent ${50 - shimmerWidth / 2}%,    rgba(255, 255, 255, 0.1) ${50 - shimmerWidth / 3}%,    ${shineColor} ${50 - shimmerWidth / 6}%,    #ffffff 50%,    ${shineColor} ${50 + shimmerWidth / 6}%,    rgba(255, 255, 255, 0.1) ${50 + shimmerWidth / 3}%,    transparent ${50 + shimmerWidth / 2}%,    transparent 100%  )`,    [angle, shimmerWidth, shineColor],  );  const uniqueId = useMemo(    () => `shiny-${Math.random().toString(36).substr(2, 9)}`,    [],  );  return (    <motion.span      ref={containerRef}      className={`relative inline-block ${className}`}      onMouseEnter={() => setIsHovering(true)}      onMouseLeave={() => setIsHovering(false)}      style={{        position: 'relative',      }}    >      {/* Base text with subtle metallic look */}      <span        className="relative z-10"        style={{          background: `linear-gradient(            180deg,            rgba(255, 255, 255, 0.95) 0%,            rgba(200, 200, 200, 0.9) 50%,            rgba(180, 180, 180, 0.85) 100%          )`,          backgroundClip: 'text',          WebkitBackgroundClip: 'text',          color: 'transparent',        }}      >        {text}      </span>      {/* Primary shine layer - bright and prominent */}      <motion.span        className="pointer-events-none absolute inset-0 z-20"        style={{          background: shimmerGradient,          backgroundSize: '300% 100%',          backgroundClip: 'text',          WebkitBackgroundClip: 'text',          color: 'transparent',        }}        initial={{ backgroundPosition: '150% 0' }}        animate={          shouldAnimate            ? {                backgroundPosition: ['-150% 0', '150% 0'],              }            : { backgroundPosition: '150% 0' }        }        transition={          shouldAnimate            ? {                duration,                ease: [0.4, 0, 0.2, 1],                repeat: trigger === 'loop' ? Infinity : 0,                repeatDelay: trigger === 'loop' ? 0.5 : 0,              }            : {}        }      >        {text}      </motion.span>      {/* Glow layer - creates the bloom effect */}      <motion.span        className="pointer-events-none absolute inset-0 z-30"        style={{          background: shimmerGradient,          backgroundSize: '300% 100%',          backgroundClip: 'text',          WebkitBackgroundClip: 'text',          color: 'transparent',          filter: 'blur(8px)',          opacity: 0.6,        }}        initial={{ backgroundPosition: '150% 0' }}        animate={          shouldAnimate            ? {                backgroundPosition: ['-150% 0', '150% 0'],              }            : { backgroundPosition: '150% 0' }        }        transition={          shouldAnimate            ? {                duration,                ease: [0.4, 0, 0.2, 1],                repeat: trigger === 'loop' ? Infinity : 0,                repeatDelay: trigger === 'loop' ? 0.5 : 0,              }            : {}        }      >        {text}      </motion.span>      {/* Extra bright center line */}      <motion.span        className="pointer-events-none absolute inset-0 z-40"        style={{          background: `linear-gradient(            ${angle}deg,            transparent 0%,            transparent 48%,            rgba(255, 255, 255, 0.9) 50%,            transparent 52%,            transparent 100%          )`,          backgroundSize: '300% 100%',          backgroundClip: 'text',          WebkitBackgroundClip: 'text',          color: 'transparent',        }}        initial={{ backgroundPosition: '150% 0' }}        animate={          shouldAnimate            ? {                backgroundPosition: ['-150% 0', '150% 0'],              }            : { backgroundPosition: '150% 0' }        }        transition={          shouldAnimate            ? {                duration,                ease: [0.4, 0, 0.2, 1],                repeat: trigger === 'loop' ? Infinity : 0,                repeatDelay: trigger === 'loop' ? 0.5 : 0,              }            : {}        }      >        {text}      </motion.span>    </motion.span>  );};export default ShinyText;

Props

Prop

Type

Examples

// Premium white shine (default)
<ShinyText
  text="Premium Quality"
  shimmerWidth={200}
  duration={3}
/>

// Gold luxury shine
<ShinyText
  text="Luxury Gold"
  shineColor="rgba(255, 215, 0, 1)"
  shimmerWidth={180}
  duration={2.5}
/>

// Interactive hover shine
<ShinyText
  text="Hover for Shine"
  trigger="hover"
  shimmerWidth={200}
/>

// Extra wide slow shine
<ShinyText
  text="Apple Vision Pro"
  shimmerWidth={250}
  duration={4}
/>

// Diagonal shine
<ShinyText
  text="Angled Shine"
  angle={45}
  shimmerWidth={150}
/>