Glowy Button
refinery/glowy-buttonFreeComponent
Button with dynamic glow that follows the cursor on hover.
Live preview
live · rendered by the registry
Rendered by refinery on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://refinery.abhii.me/r/glowy-button.jsonSource
1"use client";23import { motion, useMotionValue, useSpring, useTransform } from "motion/react";4import { cn } from "@/lib/utils";5import { ComponentProps, useRef } from "react";67type GlowVariant = "primary" | "ghost";8type GlowSize = "sm" | "md" | "lg";910export interface GlowyButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {11 variant?: GlowVariant;12 size?: GlowSize;13 colorFrom?: string;14 colorTo?: string;15 glowStrength?: number;16 ref?: React.Ref<HTMLButtonElement>;17}1819const sizeClasses: Record<GlowSize, string> = {20 sm: "h-8 px-4 text-xs gap-1.5",21 md: "h-10 px-[22px] text-sm gap-2",22 lg: "h-12 px-7 text-[15px] gap-2",23};2425const SPRING = { stiffness: 200, damping: 28, mass: 0.6 };2627const colorMix = (color: string, pct: number) =>28 `color-mix(in srgb, ${color} ${pct}%, transparent)`;2930export function GlowyButton({31 ref,32 variant = "primary",33 size = "md",34 colorFrom = "rgba(79,70,229,1)",35 colorTo = "rgba(220,80,60,1)",36 glowStrength = 1,37 className,38 children,39 onMouseMove,40 onMouseEnter,41 onMouseLeave,42 ...props43}: GlowyButtonProps) {44 const internalRef = useRef<HTMLButtonElement>(null);45 const mergedRef = (node: HTMLButtonElement | null) => {46 internalRef.current = node;47 if (typeof ref === "function") {48 ref(node);49 } else if (ref) {50 ref.current = node;51 }52 };5354 const mouseX = useMotionValue(0.5);55 const mouseY = useMotionValue(0.5);56 const smoothX = useSpring(mouseX, SPRING);57 const smoothY = useSpring(mouseY, SPRING);5859 const hovered = useMotionValue(0);60 const hoverOpacity = useSpring(hovered, { stiffness: 200, damping: 24 });6162 const ambientOpacity = useTransform(63 hoverOpacity,64 [0, 1],65 [variant === "primary" ? 0.45 : 0, 1]66 );6768 const spotOpacity = useTransform(69 hoverOpacity,70 [0, 1],71 [0, glowStrength * (variant === "primary" ? 1 : 0.85)]72 );7374 const spotLeft = useTransform(smoothX, (v) => `${v * 100}%`);75 const spotTop = useTransform(smoothY, (v) => `${v * 100}%`);7677 const ambientGradient = [78 `radial-gradient(ellipse 130% 130% at 15% 65%, ${colorMix(colorFrom, 55)} 0%, transparent 55%)`,79 `radial-gradient(ellipse 100% 100% at 88% 35%, ${colorMix(colorTo, 45)} 0%, transparent 55%)`,80 ].join(",");8182 const spotGradient =83 variant === "primary"84 ? "radial-gradient(circle 90px at 50% 50%, rgba(255,255,255,0.22) 0%, transparent 65%)"85// … truncated
What it pulls in
npm packages
Files it writes
More from refinery
All 16 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Analog Clock Screensaveranalog-clock-screensaver | refinery | Components | Free | 1 dep | |
| Avatar Circleavatar-circle | refinery | Components | Free | 1 dep | |
| DVD Screensaverdvd-screensaver | refinery | Components | Free | 1 dep | |
| Floating Cardfloating-card | refinery | Components | Free | 1 dep | |
| Floating Navfloating-nav | refinery | Components | Free | 1 dep | |
| Move To Topmove-to-top-button | refinery | Components | Free | 1 dep | |
| Notification Badgenotification-badge | refinery | Components | Free | 1 dep | |
| Sleeping Cat Screensaversleeping-cat-screensaver | refinery | Components | Free | 2 deps |
