Shiny Loader

A beautiful animated loader component with rotating gradient effects and text animations built with Tailwind CSS and Motion.dev .

Generating...

Install dependencies

npm i clsx tailwind-merge motion

Add utility file

lib/utils.ts

import { ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
 
export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

Code

ShinyLoader.tsx

"use client"
import { motion } from "motion/react"

interface LoaderProps {
  text?: string
  size?: "sm" | "md" | "lg"
  className?: string
}

const Loader = ({ text = "Generating", size = "md", className = "" }: LoaderProps) => {
  const letters = text.split("")

  const sizeConfig = {
    sm: { container: "w-[120px] h-[120px]", text: "text-sm" },
    md: { container: "w-[180px] h-[180px]", text: "text-xl" },
    lg: { container: "w-[240px] h-[240px]", text: "text-2xl" },
  }

 const letterVariants = {
  animate: {
    opacity: [0.4, 1, 0.7, 0.4],
    scale: [1, 1.15, 1, 1],
    transition: {
      duration: 2,
      repeat: Number.POSITIVE_INFINITY,
      ease: "easeInOut" as const,
    },
  },
}

const loaderVariants = {
  animate: {
    rotate: [90, 270, 450],
    transition: {
      duration: 2,
      repeat: Number.POSITIVE_INFINITY,
      ease: "easeInOut" as const,
    },
  },
}


  const currentSize = sizeConfig[size]

  return (
    <div
      className={`relative flex items-center justify-center ${currentSize.container} font-sans ${currentSize.text} font-light text-white rounded-full bg-transparent select-none ${className}`}
    >
      <div className="relative z-10 flex">
        {letters.map((letter, index) => (
          <motion.span
            key={index}
            className="inline-block opacity-40 rounded-full border-none"
            variants={letterVariants}
            animate="animate"
            transition={{
              delay: index * 0.1,
              duration: 2,
              repeat: Number.POSITIVE_INFINITY,
              ease: "easeInOut",
            }}
          >
            {letter === " " ? "\u00A0" : letter}
          </motion.span>
        ))}
      </div>

      <motion.div
        className="absolute top-0 left-0 w-full aspect-square rounded-full bg-transparent z-0"
        variants={loaderVariants}
        animate="animate"
        style={{
          boxShadow: `
            0 ${size === "sm" ? "6px" : size === "lg" ? "15px" : "10px"} ${size === "sm" ? "12px" : size === "lg" ? "25px" : "20px"} 0 #fff inset,
            0 ${size === "sm" ? "12px" : size === "lg" ? "25px" : "20px"} ${size === "sm" ? "18px" : size === "lg" ? "35px" : "30px"} 0 #ad5fff inset,
            0 ${size === "sm" ? "35px" : size === "lg" ? "75px" : "60px"} ${size === "sm" ? "35px" : size === "lg" ? "75px" : "60px"} 0 #471eec inset
          `,
        }}
      />
    </div>
  )
}

export default Loader

Props

PropTypeDefaultDescription
textstring"Generating"The text to display in the loader
size"sm" | "md" | "lg""md"Size variant of the loader
classNamestring""Additional CSS classes

Size Specifications

SizeContainerText Size
sm120x120pxtext-sm
md180x180pxtext-xl
lg240x240pxtext-2xl
Shiny-Loader16