Interactive 3D Spring TiltExposed Cavity Slot

Tactile Pill Popped-Up Button

Skeuomorphic tactile pill button featuring mechanical spring tilt, recessed cavity slot reveal, and glowing radiant LED status beacon.

preview.tsx
Interactions:0
Hover or click to interact

Customizer

PRESETS & VARIATIONS

All Variants Preview

Hover & click buttons to trigger -9.23° spring tilt & slot depth cavity depression

Figma Cyan Beaconvariant="default"
1:1 Figma Master design with turquoise indicator dot
UI Pirate Magmavariant="orange"
Signature magma orange pill cap with glowing amber beacon
Dark Obsidianvariant="dark"
Stealth midnight pill with violet status indicator
Cyberpunk Matrixvariant="cyberpunk"
Neon reactor green beacon with tactile recessed tray
Minimal Cleanvariant="minimal"
Crisp clean tactile pill with sapphire status beacon
Tilted State PreviewstateMode="tilted"
Fixed mechanical spring tilt position (-9.23° angle)

Installation & Setup

Install required peer dependencies:

npm install framer-motion clsx

Code & Integration

TactilePillButton.tsx• Production Ready
"use client";

import React, { useState } from "react";
import { motion } from "framer-motion";

export type TactileButtonVariant = "default" | "dark" | "orange" | "cyberpunk" | "minimal";
export type TactileButtonState = "interactive" | "resting" | "tilted";

export interface TactilePillButtonProps {
  label?: string;
  dotColor?: string;
  variant?: TactileButtonVariant;
  size?: "xs" | "sm" | "md" | "lg" | "xl";
  tiltAngle?: number;
  onClick?: () => void;
  className?: string;
}

export function TactilePillButton({
  label = "Get Started",
  dotColor = "#54EAD8",
  variant = "default",
  size = "md",
  tiltAngle = -9.23,
  onClick,
  className = "",
}: TactilePillButtonProps) {
  const [isHovered, setIsHovered] = useState(false);
  const [isPressed, setIsPressed] = useState(false);

  return (
    <div
      className={`relative inline-block select-none ${className}`}
      onMouseEnter={() => setIsHovered(true)}
      onMouseLeave={() => {
        setIsHovered(false);
        setIsPressed(false);
      }}
    >
      {/* Recessed Cavity Base Slot */}
      <div className="absolute inset-0 rounded-[16px] bg-[#D4D4D8] shadow-[inset_0_2px_4px_rgba(0,0,0,0.3)]" />

      {/* Tactile Cap with Lift & Tilt */}
      <motion.button
        type="button"
        onClick={onClick}
        onMouseDown={() => setIsPressed(true)}
        onMouseUp={() => setIsPressed(false)}
        animate={{
          rotate: isHovered ? tiltAngle : 0,
          y: isPressed ? 2 : isHovered ? -14 : 0,
          x: isHovered ? -4 : 0,
        }}
        transition={{ type: "spring", stiffness: 450, damping: 25 }}
        className="relative flex items-center gap-3 px-6 py-3 rounded-[16px] bg-[#EAEAEA] border border-white text-gray-800 font-bold text-sm shadow-[0_8px_16px_rgba(0,0,0,0.15)] cursor-pointer focus:outline-none"
      >
        <span
          className="w-2.5 h-2.5 rounded-full"
          style={{
            backgroundColor: dotColor,
            boxShadow: `0 0 8px ${dotColor}`,
          }}
        />
        <span>{label}</span>
      </motion.button>
    </div>
  );
}

export default TactilePillButton;

Component API Reference

PropTypeDefaultDescription
labelstring"Get Started"Text displayed on the button cap
dotColorstring"#54EAD8"Hex color of the beacon LED indicator
tiltAnglenumber-9.23Hover tilt angle in degrees
size"xs" | "sm" | "md" | "lg" | "xl""md"Scale multiplier
onClick() => voidundefinedClick callback event handler

Personalized Help

Struggling with 3D tactile spring buttons or component libraries? 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.