All components

Rainbow Button

CTA cycling the brand ramp, with a matching glow beneath.

0.8 KB gzippedZero dependenciesReduced-motion safeBase UI & Radix compatible

Installation

npx shadcn@latest add https://innsite.com.mx/r/rainbow-button.json

Source

import { cn } from "@/lib/utils";

interface RainbowButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  /** Seconds for one full colour cycle */
  speed?: number;
  children: React.ReactNode;
}

/**
 * CTA with a colour ramp that cycles through the brand gradient and casts a
 * matching glow beneath it. Zero dependencies — the motion is one keyframe.
 */
export function RainbowButton({
  speed = 4,
  children,
  className,
  style,
  ...props
}: RainbowButtonProps) {
  return (
    <button
      {...props}
      data-slot="rainbow-button"
      style={{ "--rainbow-duration": `${speed}s`, ...style } as React.CSSProperties}
      className={cn(
        "group relative inline-flex h-11 cursor-pointer items-center justify-center rounded-xl px-6 text-sm font-medium text-brand-foreground transition-transform focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand active:scale-[0.98] disabled:pointer-events-none disabled:opacity-50",
        // The ramp itself, plus a blurred copy behind it for the glow.
        "animate-rainbow bg-[linear-gradient(90deg,var(--brand-from),var(--brand-via),var(--brand-to),var(--brand-via),var(--brand-from))] bg-[length:200%_100%]",
        "before:absolute before:inset-x-3 before:-bottom-1 before:-z-10 before:h-full before:animate-rainbow before:bg-[linear-gradient(90deg,var(--brand-from),var(--brand-via),var(--brand-to),var(--brand-via),var(--brand-from))] before:bg-[length:200%_100%] before:blur-lg before:transition-opacity before:content-[''] before:opacity-60 hover:before:opacity-90",
        className
      )}
    >
      {children}
    </button>
  );
}