←
Elevated Underglow 3D Button

Elevated Underglow 3D Button

Tactile Elevation

Interactive 3D tactile pill button that elevates 13px on hover to reveal a glowing electric blue extruded sub-chassis, bottom reflection rim, and realistic clay elevation physics.

Interactive Playground & Studio

Live Controls
elevated-underglow-cta.tsx
Hover or click to interact
Customizer
PRESETS & VARIATIONS

All Variants & Themes

Click to test interactive spring physics on every theme

Default Electric Bluetheme="default"

1:1 reference 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.

Features & Physics

✓13px dynamic vertical spring elevation on hover
✓Illuminated electric blue sub-chassis rim
✓Tactile phone / call icon with specular highlights
✓Soft diffuse claymorphic shadow stack

Code & Integration

Customized live with your active playground prop settings:

"use client";

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

export type ElevatedUnderglowTheme =
  | "default"
  | "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 = {
  default: {
    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 = "default",
  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.default;

  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>
  );
}

Peer Dependencies

Requires Framer Motion and Tailwind CSS for spring physics and layout tokens:

npm install framer-motion clsx lucide-react tailwind-merge

API & Props Reference

PropTypeDefaultDescription
labelstring"Book A Call"Text displayed on the elevated button face.
icon"phone" | "calendar" | "arrow" | "sparkle" | "mail" | "none""phone"Leading icon displayed next to the label.
liftAmountnumber13Optional lift distance in pixels on hover (default: 13 matching spec 55:40).
theme"default" | "uipirate" | "emerald" | "violet" | "crimson" | "dark""default"Color theme for the underglow beam and reflection rim.
size"xs" | "sm" | "md" | "lg" | "xl""md"Size dimensions of the pill.