Components / Spider Button

Spider Button

Comic book-style interactive buttons inspired by Spider-Man aesthetics. Features glitch text effects on hover, chromatic aberration animations, custom cursors, and a satisfying tap animation. Five color variants available.

Button Variants

Default

Classic comic book yellow

Primary

Main call-to-action

Secondary

Alternate actions

Success

Positive operations

Warning

Caution needed

Tip: Hover over buttons to see the glitch effect and custom cursor. Click to see the tap animation and "CLICK" text popup.

Real-World Examples

Play Action

Submit Form

Delete Action

Save Action

Usage

tsx
import SpiderButton from "@/components/spiderman-theme-buttons/spider-button"

export function Example() {
  const handleClick = (e: React.MouseEvent) => {
    console.log('Button clicked!', e)
  }

  return (
    <SpiderButton
      buttonName="CLICK ME"
      hoverBtnName="DO IT!"
      variant="primary"
      handleButtonClick={handleClick}
    />
  )
}

Props

PropTypeDescription
buttonNamestringDefault text displayed on the button
hoverBtnNamestringText shown when hovering over the button
variant'default' | 'primary' | 'secondary' | 'success' | 'warning'Color variant (default: 'default')
handleButtonClick(e: any) => voidClick handler function
btnClassNamestring?Additional CSS classes for the button

Features

  • Glitch Effect — Text shakes with chromatic aberration on hover
  • Custom Cursors — Comic-style cursor on hover, click cursor on press
  • Click Popup — "CLICK" text appears above button on tap
  • 5 Variants — Default (yellow), Primary (blue), Secondary (purple), Success (green), Warning (red)
  • Random Shake — Each button instance has unique shake intensity
  • SSR Safe — Hydration-safe with proper mounting detection

Dependencies

This component requires the motion/react library for animations. Install it with:

bash
pnpm add motion

Required Assets

Place these cursor and click images in your public/buttons/spiderman/ folder:

  • pointer.png — Custom hover cursor
  • clicked.png — Custom click cursor
  • click.png — Click popup text image

Source Code

This component requires 3 files. Copy all into your components/spiderman-theme-buttons/ folder.

tsx
'use client'
import { useState, useEffect } from "react";
import { motion } from "motion/react";
import style from "./spider-button.module.css";
import { buttonAnim, clickAnim } from "./spiderbtn-animation";

export type SpidermanButtonProps = {
    buttonName: string;
    hoverBtnName: string;
    btnClassName?: string;
    variant?: 'primary' | 'secondary' | 'success' | 'warning' | 'default';
    handleButtonClick: (e: any) => void;
}

export const RANDOM_INT = (min: number, max: number): number => 
    Math.floor(Math.random() * (max - min + 1) + min);

export default function SpiderButton({ 
    buttonName, 
    hoverBtnName, 
    btnClassName, 
    variant = 'default', 
    handleButtonClick 
}: SpidermanButtonProps) {
    const [btnName, setBtnName] = useState(buttonName);
    const [shakeAmount, setShakeAmount] = useState(8);
    const [clickOffset, setClickOffset] = useState(0);
    const [isMounted, setIsMounted] = useState(false);

    useEffect(() => {
        setShakeAmount(RANDOM_INT(6, 12));
        setClickOffset(RANDOM_INT(-50, 50));
        setIsMounted(true);
    }, []);

    const getButtonClassName = () => {
        let className = style.btn;
        if (variant !== 'default') {
            className += ` ${style[variant]}`;
        }
        if (btnClassName) {
            className += ` ${btnClassName}`;
        }
        return className;
    };

    if (!isMounted) {
        return (
            <button type="button" className={getButtonClassName()} onClick={handleButtonClick}>
                {buttonName}
            </button>
        );
    }

    return (
        <motion.button
            type="button"
            className={getButtonClassName()}
            initial="init"
            animate="init"
            whileHover="hover"
            whileTap="tap"
            whileFocus="focus"
            variants={buttonAnim}
            custom={shakeAmount}
            onMouseEnter={() => setBtnName(hoverBtnName)}
            onMouseLeave={() => setBtnName(buttonName)}
            onClick={handleButtonClick}
        >
            {btnName}
            <motion.div className={style.click} variants={clickAnim} custom={clickOffset} />
        </motion.button>
    );
}