Gradient Border Button
A rainbow gradient endlessly rotates around the button edge.
components/ui/gradient-border-button.tsx
"use client";
import { motion } from "motion/react";
import { Sparkles } from "lucide-react";
import type { ButtonHTMLAttributes } from "react";
type GradientBorderButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
/** Seconds per full rotation of the border gradient */
speed?: number;
};
export function GradientBorderButton({ children, className = "", speed = 3, ...props }: GradientBorderButtonProps) {
return (
<button className={`group relative inline-flex overflow-hidden rounded-full p-[1.5px] transition-transform hover:-translate-y-0.5 ${className}`} {...props}>
<motion.span
aria-hidden
className="absolute left-1/2 top-1/2 aspect-square w-[300%] bg-[conic-gradient(from_0deg,#3b82f6,#8b5cf6,#ec4899,#f59e0b,#3b82f6)]"
style={{ x: "-50%", y: "-50%" }}
animate={{ rotate: 360 }}
transition={{ duration: speed, repeat: Infinity, ease: "linear" }}
/>
<span className="relative inline-flex items-center gap-2 rounded-full bg-white px-6 py-3 text-sm font-medium text-zinc-900 transition-colors group-hover:bg-zinc-50">
{children}
</span>
</button>
);
}
export default function Demo() {
return (
<GradientBorderButton>
<Sparkles className="size-4 text-violet-600" />
Try Kinetiq Pro
</GradientBorderButton>
);
}
Installation
Install the dependencies
$ npm i motion lucide-reactCopy the source into
components/ui/gradient-border-button.tsxcomponents/ui/gradient-border-button.tsx"use client"; import { motion } from "motion/react"; import { Sparkles } from "lucide-react"; import type { ButtonHTMLAttributes } from "react"; type GradientBorderButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & { /** Seconds per full rotation of the border gradient */ speed?: number; }; export function GradientBorderButton({ children, className = "", speed = 3, ...props }: GradientBorderButtonProps) { return ( <button className={`group relative inline-flex overflow-hidden rounded-full p-[1.5px] transition-transform hover:-translate-y-0.5 ${className}`} {...props}> <motion.span aria-hidden className="absolute left-1/2 top-1/2 aspect-square w-[300%] bg-[conic-gradient(from_0deg,#3b82f6,#8b5cf6,#ec4899,#f59e0b,#3b82f6)]" style={{ x: "-50%", y: "-50%" }} animate={{ rotate: 360 }} transition={{ duration: speed, repeat: Infinity, ease: "linear" }} /> <span className="relative inline-flex items-center gap-2 rounded-full bg-white px-6 py-3 text-sm font-medium text-zinc-900 transition-colors group-hover:bg-zinc-50"> {children} </span> </button> ); } export default function Demo() { return ( <GradientBorderButton> <Sparkles className="size-4 text-violet-600" /> Try Kinetiq Pro </GradientBorderButton> ); }Use it
The file exports the component and a
Demoshowing typical usage. Import whichever you need.