TetraKits UI Magic UI Shiny Button ← Library

Magic UI Shiny Button

21st.dev magicui/shiny-button: looping CSS mask shimmer across violet highlight, hover lift + ring glow. “Copy free TSX” primary CTA.

shiny buttonmagic ui shimmer21st dev buttonanimated cta reactframer motion button
Live preview

Dependencies

react framer-motion
npm install framer-motion
"use client";

import { motion, type AnimationProps } from "framer-motion";

function cn(...inputs: (string | undefined | null | false)[]) {
  return inputs.filter(Boolean).join(" ");
}

const shineProps: AnimationProps = {
  initial: { "--x": "100%", scale: 0.96 },
  animate: { "--x": "-100%", scale: 1 },
  whileHover: { scale: 1.04, y: -2, boxShadow: "0 12px 40px rgba(139,92,246,0.25)" },
  whileTap: { scale: 0.95 },
  transition: {
    repeat: Infinity,
    repeatType: "loop",
    repeatDelay: 1.2,
    type: "spring",
    stiffness: 20,
    damping: 15,
    mass: 2,
  },
};

export function ShinyCtaButton({ children = "Copy free TSX" }: { children?: React.ReactNode }) {
  return (
    <motion.button
      {...shineProps}
      style={{ "--x": "100%" } as React.CSSProperties}
      className={cn(
        "relative rounded-xl px-7 py-3 font-semibold",
        "bg-zinc-900 shadow-lg ring-1 ring-white/10",
        "transition-shadow duration-300 hover:ring-violet-500/30"
      )}
    >
      <span
        className="relative block text-sm tracking-wide text-white/90"
        style={{
          maskImage:
            "linear-gradient(-75deg,#a78bfa calc(var(--x) + 20%),transparent calc(var(--x) + 30%),#c4b5fd calc(var(--x) + 100%))",
        }}
      >
        {children}
      </span>
      <span
        style={{
          mask: "linear-gradient(#000,#000) content-box, linear-gradient(#000,#000)",
          maskComposite: "exclude",
        }}
        className="absolute inset-0 z-10 block rounded-[inherit] bg-[linear-gradient(-75deg,rgba(167,139,250,0.15)_calc(var(--x)+20%),rgba(167,139,250,0.55)_calc(var(--x)+25%),rgba(167,139,250,0.15)_calc(var(--x)+100%))] p-px"
      />
    </motion.button>
  );
}