buttons

Glow Button

A high-performance interactive button with radial glow and hover tracking effects.

Loading preview
Advertisement
Ad space reserved for a future placement

Source code

"use client";

import type { ButtonHTMLAttributes, CSSProperties, ReactNode } from "react";

type GlowButtonSize = "sm" | "md" | "lg";

interface GlowButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "color"> {
  children: ReactNode;
  glowColor?: string;
  size?: GlowButtonSize;
  pulse?: boolean;
}

const SIZE_CLASSES: Record<GlowButtonSize, string> = {
  sm: "px-4 py-2 text-sm",
  md: "px-6 py-3 text-base",
  lg: "px-8 py-4 text-lg",
};

export function GlowButton({
  children,
  glowColor = "#8b5cf6",
  size = "md",
  pulse = true,
  className,
  style,
  ...props
}: GlowButtonProps) {
  const classNames = ["glow-button", SIZE_CLASSES[size], pulse ? "glow-button--pulse" : "", className]
    .filter(Boolean)
    .join(" ");

  const glowStyle: CSSProperties = {
    ...style,
    ["--glow-color" as string]: glowColor,
  };

  return (
    <button type="button" className={classNames} style={glowStyle} {...props}>
      <span className="glow-button-label">{children}</span>
      <style jsx>{`
        .glow-button {
          position: relative;
          display: inline-flex;
          align-items: center;
          justify-content: center;
          border-radius: 9999px;
          border: 1px solid color-mix(in srgb, var(--glow-color) 45%, white);
          background-color: color-mix(in srgb, var(--glow-color) 12%, white);
          color: color-mix(in srgb, var(--glow-color) 65%, black);
          font-weight: 600;
          cursor: pointer;
          box-shadow: 0 0 14px 2px color-mix(in srgb, var(--glow-color) 25%, transparent);
          transition:
            transform 200ms ease,
            box-shadow 200ms ease,
            background-color 200ms ease;
        }

        .glow-button--pulse {
          animation: glow-button-pulse 2.4s ease-in-out infinite;
        }

        .glow-button:hover {
          animation-play-state: paused;
          transform: translateY(-1px) scale(1.03);
          background-color: color-mix(in srgb, var(--glow-color) 18%, white);
          box-shadow: 0 0 28px 6px color-mix(in srgb, var(--glow-color) 45%, transparent);
        }

        .glow-button:active {
          transform: translateY(0) scale(0.98);
        }

        .glow-button:focus-visible {
          outline: 2px solid var(--glow-color);
          outline-offset: 2px;
        }

        .glow-button:disabled {
          cursor: not-allowed;
          opacity: 0.5;
          animation: none;
          transform: none;
        }

        .glow-button-label {
          position: relative;
          z-index: 1;
        }

        @keyframes glow-button-pulse {
          0%,
          100% {
            box-shadow: 0 0 14px 2px color-mix(in srgb, var(--glow-color) 25%, transparent);
          }
          50% {
            box-shadow: 0 0 22px 6px color-mix(in srgb, var(--glow-color) 40%, transparent);
          }
        }

        @media (prefers-reduced-motion: reduce) {
          .glow-button,
          .glow-button--pulse {
            animation: none;
            transition: none;
          }
        }
      `}</style>
    </button>
  );
}

Usage

Import the component and use it like this.

import { GlowButton } from "./GlowButton";

export default function Example() {
  return (
    <GlowButton glowColor="#8b5cf6" size="md">
      Get started
    </GlowButton>
  );
}

Dependencies

No external dependencies.