Interactive 3D Spring Tilt•Exposed 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"
UI Pirate Magmavariant="orange"
Dark Obsidianvariant="dark"
Cyberpunk Matrixvariant="cyberpunk"
Minimal Cleanvariant="minimal"
Tilted State PreviewstateMode="tilted"
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
| Prop | Type | Default | Description |
|---|---|---|---|
| label | string | "Get Started" | Text displayed on the button cap |
| dotColor | string | "#54EAD8" | Hex color of the beacon LED indicator |
| tiltAngle | number | -9.23 | Hover tilt angle in degrees |
| size | "xs" | "sm" | "md" | "lg" | "xl" | "md" | Scale multiplier |
| onClick | () => void | undefined | Click 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.