Interactive 3D Spring ButtonReact + Framer Motion

Elevated Underglow 3D CTA Button

Multi-tier 3D CTA button featuring 13px spring elevation, dynamic base underglow flare, and specular reflection bottom insets.

preview.tsx
Interactions:0
Hover or click to interact

Customizer

PRESETS & VARIATIONS

All Variants Preview

Hover over each button to trigger realistic 13px 3D lift physics

Figma Electric Bluetheme="figma"
1:1 Figma Master design with blue extruded sub-chassis
UI Pirate Magmatheme="uipirate"
Vibrant signature brand magma orange glow
Neon Emeraldtheme="emerald"
High-tech reactor matrix green elevation chassis
Cyber Violettheme="violet"
Sleek neon ultraviolet sub-chassis underglow
Crimson Embertheme="crimson"
Punchy ruby red extruded sub-surface illumination
Dark Obsidiantheme="dark"
Monochrome stealth obsidian cap with pure white glow

Installation & Setup

Install the required dependencies for Framer Motion spring physics and Lucide icons:

npm install framer-motion clsx lucide-react

Code & Integration

ElevatedUnderglowCTA.tsx• Production Ready
"use client";

import React, { useState } from "react";
import { motion } from "framer-motion";
import { Phone, Calendar, ArrowRight, Sparkles, Mail } from "lucide-react";

export type ElevatedUnderglowTheme =
  | "figma"
  | "uipirate"
  | "cyan"
  | "emerald"
  | "violet"
  | "crimson"
  | "amber"
  | "dark";

export type ElevatedUnderglowSize = "xs" | "sm" | "md" | "lg" | "xl";
export type ElevatedUnderglowIconType = "phone" | "calendar" | "arrow" | "sparkle" | "mail" | "none";

export interface ElevatedUnderglowCTAProps {
  label?: string;
  icon?: ElevatedUnderglowIconType | React.ReactNode;
  theme?: ElevatedUnderglowTheme;
  size?: ElevatedUnderglowSize;
  onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
  disabled?: boolean;
  className?: string;
}

export const UNDERGLOW_THEMES = {
  figma: {
    primaryColor: "#0077FF",
    baseBg: "bg-[#0077FF]",
    capBg: "bg-[#e8e8e8]",
    capBorder: "border-[#efefef]",
    capText: "text-[#353535]",
  },
  uipirate: {
    primaryColor: "#FF5B04",
    baseBg: "bg-[#FF5B04]",
    capBg: "bg-[#f0ece7]",
    capBorder: "border-[#fbf8f5]",
    capText: "text-[#26211d]",
  },
  cyan: {
    primaryColor: "#06B6D4",
    baseBg: "bg-[#06B6D4]",
    capBg: "bg-[#e6f4f8]",
    capBorder: "border-[#f0f9fb]",
    capText: "text-[#164e63]",
  },
};

export function ElevatedUnderglowCTA({
  label = "Book A Call",
  icon = "phone",
  theme = "figma",
  size = "md",
  onClick,
  disabled = false,
  className = "",
}: ElevatedUnderglowCTAProps) {
  const [isHovered, setIsHovered] = useState(false);
  const [isPressed, setIsPressed] = useState(false);

  const t = UNDERGLOW_THEMES[theme as keyof typeof UNDERGLOW_THEMES] || UNDERGLOW_THEMES.figma;

  const renderIcon = () => {
    if (typeof icon !== "string") return icon;
    switch (icon) {
      case "phone": return <Phone className="w-4 h-4" />;
      case "calendar": return <Calendar className="w-4 h-4" />;
      case "arrow": return <ArrowRight className="w-4 h-4" />;
      case "sparkle": return <Sparkles className="w-4 h-4" />;
      case "mail": return <Mail className="w-4 h-4" />;
      default: return null;
    }
  };

  return (
    <div
      className={`relative inline-block select-none ${className}`}
      onMouseEnter={() => setIsHovered(true)}
      onMouseLeave={() => {
        setIsHovered(false);
        setIsPressed(false);
      }}
    >
      {/* 3D Underglow Base Extrusion */}
      <div
        className={`absolute inset-0 rounded-[35px] ${t.baseBg} transition-opacity duration-300 ${
          isHovered ? "opacity-100" : "opacity-0"
        }`}
        style={{
          boxShadow: `0px 21px 12px 0px ${t.primaryColor}26, 0px 9px 9px 0px ${t.primaryColor}42`,
        }}
      />

      {/* Floating Cap Button */}
      <motion.button
        type="button"
        disabled={disabled}
        onClick={onClick}
        onMouseDown={() => setIsPressed(true)}
        onMouseUp={() => setIsPressed(false)}
        animate={{
          y: isPressed ? 2 : isHovered ? -13 : 0,
        }}
        transition={{ type: "spring", stiffness: 450, damping: 25 }}
        className={`relative flex items-center justify-center gap-3 px-6 py-3.5 rounded-[35px] ${t.capBg} ${t.capBorder} border ${t.capText} font-semibold text-sm cursor-pointer shadow-lg`}
      >
        {renderIcon()}
        <span>{label}</span>
      </motion.button>
    </div>
  );
}

Component API Reference

PropTypeDefaultDescription
labelstring"Book A Call"Text displayed inside the button
icon"phone" | "calendar" | "arrow" | "sparkle" | "mail" | ReactNode"phone"Leading icon glyph or custom React node
themeElevatedUnderglowTheme"figma"Colorway theme preset (Electric Blue, Orange, Cyan, etc.)
size"xs" | "sm" | "md" | "lg" | "xl""md"Scale multiplier
onClick(e) => voidundefinedClick callback event handler

Personalized Help

Struggling with elevated 3D underglow buttons or interactive UI controls? Let's talk about your product.

UI Pirate is a product design & development agency trusted by 50+ SaaS founders and enterprise teams across the US, UK & beyond. Tell us what you need.