# Hover Glow Button

> A blurred glow spot follows the cursor across the button; glow color is adjustable.

- Author: Atelier UI
- License: MIT
- Page: https://chromotion.dev/en/components/hover-glow-button
- Site: Atelier UI (https://chromotion.dev)

## Install

```bash
npx shadcn@latest add https://chromotion.dev/r/hover-glow-button.json
```

Stack: React + TypeScript + Tailwind CSS v4, shadcn/ui conventions. `cn` comes from `@/lib/utils`.

## Dependencies

No extra dependencies.

## Usage

```tsx title="components/hover-glow-button-demo.tsx"
import { HoverGlowButton } from "@/components/hover-glow-button"

export default function HoverGlowButtonDemo() {
  return (
    <div className="flex flex-wrap items-center justify-center gap-4 p-8">
      <HoverGlowButton>Hover me</HoverGlowButton>
      <HoverGlowButton glowColor="#f43f5e">Rose glow</HoverGlowButton>
      <HoverGlowButton glowColor="#10b981">Emerald glow</HoverGlowButton>
    </div>
  )
}
```

## Source

```tsx title="components/hover-glow-button.tsx"
"use client"

import * as React from "react"

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

export interface HoverGlowButtonProps extends React.ComponentProps<"button"> {
  /** Color of the glow that follows the cursor */
  glowColor?: string
}

export function HoverGlowButton({
  glowColor = "#3b82f6",
  className,
  children,
  onMouseMove,
  ...props
}: HoverGlowButtonProps) {
  const glowRef = React.useRef<HTMLSpanElement>(null)

  function handleMouseMove(event: React.MouseEvent<HTMLButtonElement>) {
    const rect = event.currentTarget.getBoundingClientRect()
    const glow = glowRef.current
    if (glow) {
      glow.style.setProperty("--glow-x", `${event.clientX - rect.left}px`)
      glow.style.setProperty("--glow-y", `${event.clientY - rect.top}px`)
    }
    onMouseMove?.(event)
  }

  return (
    <button
      className={cn(
        "group relative inline-flex h-12 items-center justify-center overflow-hidden rounded-xl border border-border bg-card px-8 text-sm font-medium text-card-foreground",
        "transition-transform duration-200 active:scale-[0.98]",
        "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background focus-visible:outline-none",
        "disabled:pointer-events-none disabled:opacity-50",
        className
      )}
      onMouseMove={handleMouseMove}
      {...props}
    >
      <span
        ref={glowRef}
        aria-hidden
        className="pointer-events-none absolute inset-0 opacity-0 blur-md transition-opacity duration-300 group-hover:opacity-100"
        style={{
          background: `radial-gradient(90px circle at var(--glow-x, 50%) var(--glow-y, 50%), ${glowColor}, transparent 70%)`,
        }}
      />
      <span aria-hidden className="pointer-events-none absolute inset-px rounded-[11px] bg-card/80" />
      <span className="relative inline-flex items-center gap-2">{children}</span>
    </button>
  )
}
```
