Advertisement

Mouse-Tracking Linear Shine Button

| | 2 min read | code by Tim Wilson
A11y Ready Intermediate

Tech & Dependencies

HTML CSS TypeScript
React React DOM Tailwind CSS

Features

  • Mouse Tracking
  • Radial Gradients

Browser Support

Chrome 49+ Edge 79+ Firefox 32+ Safari 8+

Core

This Mouse-Tracking Linear Shine Button adds a high-end, tactile feel to your UI. Unlike standard hover effects that simply swap colors, this component tracks the user’s cursor position to drag a realistic light reflection across the button’s surface. Built with React and Tailwind CSS, it utilizes reactive CSS variables to control gradient positions, creating a dynamic lighting effect that feels physical and responsive.

Core Technique

The effect relies on passing the mouse coordinates from React state to CSS variables.

  1. Coordinate Normalization: The mouseMove function calculates the cursor’s position within the button as a percentage (0.0 to 1.0) using getBoundingClientRect.
  2. Reactive Styles: These values are passed to the inline style attribute as --mx (mouse X) and --my (mouse Y).
  3. The Shine: The .shine class uses a repeating-linear-gradient with mix-blend-mode: screen. Its background-position is directly linked to the CSS variables, causing the stripes to follow the mouse.
  4. The Glow: The .glow class creates two opposing radial-gradient lights on the top and bottom edges. Interestingly, the calculation calc(50% - var(--mx)) moves these glows in the opposite direction of the mouse, adding depth and parallax.

Customization

To change the look of the reflection, modify the CSS gradient in the .shine class. You can adjust the angle (125deg) or the colors.

.shine {
  /* Change 125deg to vertical (180deg) or horizontal (90deg) */
  background-image: repeating-linear-gradient(
      125deg, 
      transparent 0%,
      rgba(255, 215, 0, 0.3) 25%, /* Gold tint */
      transparent 50%
  );
}

To control the intensity of the effect, adjust the opacity in the Tailwind classes or the CSS.

// Change opacity-100 to opacity-50 for a subtler effect
<div className="absolute inset-0 opacity-0 group-hover:opacity-100 ...">

Tips

1. Performance Optimization: Currently, this component uses useState to track mouse movement. This triggers a React re-render on every pixel the mouse moves, which can be heavy if you have many buttons. A more performant approach is to manipulate the DOM directly via ref.

const mouseMove = (e) => {
    if (!buttonRef.current) return;
    const rect = buttonRef.current.getBoundingClientRect();
    const x = (e.clientX - rect.left) / rect.width;
    const y = (e.clientY - rect.top) / rect.height;
    // Update CSS variables directly without re-render
    buttonRef.current.style.setProperty("--mx", `${x * 100}%`);
    buttonRef.current.style.setProperty("--my", `${y * 100}%`);
};

2. Accessibility: The group-hover utility in Tailwind only targets mouse interaction. To make this keyboard accessible, ensure you add group-focus:opacity-100 alongside group-hover, so keyboard users (Tab navigation) can also see the active state (though the specific mouse-tracking effect won’t apply, the visibility will).

Advertisement