React Example: Button Press with Spring Transition — Full Implementation Guide

Use Motion (formerly Framer Motion) with a spring configuration of { type: "spring", duration: 0.5, bounce: 0.2 } and animate scale from 1 to 0.97 on press for a natural, interruptible button interaction.

The Skills repository by Emil Kowalski is a curated collection of design-engineered patterns for building high-quality UI components. When implementing a React button press with spring transition, the repository provides a complete workflow—from library selection to exact spring values—ensuring your interactions feel alive and consistent with modern design standards.


Why Spring Physics Matter for Button Presses

The Skills system emphasizes spring-driven motion over traditional easing curves for interactive feedback. According to the repository's standards in skills/review-animations/STANDARDS.md, springs provide three critical advantages:

  • Interruptibility — If a user releases the button mid-animation, the spring preserves momentum and finishes naturally rather than snapping to a keyframe endpoint
  • Physicality — Simulated inertia makes the UI feel tactile and responsive, as documented in the Physicality section of skills/review-animations/STANDARDS.md
  • Consistency — All interactive elements (modals, drawers, buttons) share the same spring configuration, creating a unified visual language

The repository's skills/pick-ui-library/SKILL.md explicitly recommends Motion (formerly Framer Motion) for spring-based UI interactions. Motion's useSpring hook provides velocity-preserving animations that align with the Skills design philosophy.

Key imports for this implementation:

import { motion, useSpring, useMotionValue } from "framer-motion";

The Canonical Spring Configuration

Per skills/review-animations/STANDARDS.md (lines 65–70), the Apple-style spring is the repository's default for press interactions:

const springConfig = { type: "spring", duration: 0.5, bounce: 0.2 };

This configuration balances responsiveness with polish—fast enough to feel snappy, bouncy enough to feel organic.


Complete React Button Implementation

Below is a production-ready component adapted from skills/emil-design-eng/SKILL.md that implements the Skills button press pattern:

import { motion, useSpring, useMotionValue } from "framer-motion";

export default function PressableButton({
  children,
  onClick,
}: {
  children: React.ReactNode;
  onClick?: () => void;
}) {
  // Spring config from STANDARDS.md — Apple-style spring
  const springConfig = { type: "spring", duration: 0.5, bounce: 0.2 };
  const scale = useSpring(1, springConfig);
  const isPressed = useMotionValue(false);

  // 0.97 scale matches the "button-press feedback" standard
  const handlePressStart = () => {
    isPressed.set(true);
    scale.set(0.97);
  };

  const handlePressEnd = () => {
    isPressed.set(false);
    scale.set(1);
  };

  return (
    <motion.button
      style={{ scale }}
      onPointerDown={handlePressStart}
      onPointerUp={handlePressEnd}
      onPointerLeave={handlePressEnd}
      onClick={onClick}
      transition={springConfig}
      className="px-4 py-2 bg-blue-600 text-white rounded"
    >
      {children}
    </motion.button>
  );
}

Implementation breakdown

Step Repository Reference Purpose
Import motion, useSpring skills/pick-ui-library/SKILL.md Use the recommended animation library
Define springConfig object skills/review-animations/STANDARDS.md Apply the canonical Apple-style spring values
Initialize scale with useSpring(1, springConfig) skills/emil-design-eng/SKILL.md Create a velocity-aware animated value
Set scale.set(0.97) on press skills/emil-design-eng/SKILL.md Apply subtle press feedback (3% reduction)
Use onPointerDown/Up/Leave skills/review-animations/STANDARDS.md Ensure interruptible, physically accurate motion

Alternative: The CSS Fallback Pattern

The Skills repository also documents a progressive enhancement strategy in skills/emil-design-eng/SKILL.md. For environments without JavaScript or when Motion fails to load, apply a CSS-based press state:

button:active {
  transform: scale(0.97);
  transition: transform 0.2s ease-out;
}

This provides immediate feedback while the spring-enhanced version delivers the polished experience for capable browsers.


Key Repository Files

File Path Relevance to Button Press Implementation
README.md Repository philosophy and skill index
skills/pick-ui-library/SKILL.md Motion library recommendation
skills/animate/SKILL.md Spring configuration theory and timing tables
skills/review-animations/STANDARDS.md Exact spring values (duration: 0.5, bounce: 0.2)
skills/emil-design-eng/SKILL.md Concrete useSpring examples and JSX patterns

Summary

  • Library choice: Motion (useSpring, useMotionValue) per skills/pick-ui-library/SKILL.md
  • Spring config: { type: "spring", duration: 0.5, bounce: 0.2 } from skills/review-animations/STANDARDS.md
  • Press transform: scale(0.97) for subtle, consistent feedback
  • Implementation pattern: onPointerDown/Up handlers with scale.set() for full interruptibility
  • Fallback: CSS :active state for progressive enhancement

Frequently Asked Questions

What makes a spring transition better than a CSS transition for button presses?

A spring transition preserves velocity when interrupted. According to skills/review-animations/STANDARDS.md, if a user releases a button before the press animation completes, a spring continues from its current momentum rather than restarting or snapping, creating natural physical motion that CSS transitions cannot replicate.

Can I use whileTap instead of manual pointer handlers?

Yes—motion.button supports whileTap={{ scale: 0.97 }} with the same transition prop. However, the Skills repository's skills/emil-design-eng/SKILL.md demonstrates explicit handlers to illustrate spring configuration control and ensure readability for complex interactions where additional logic may be needed.

What if I need a different press scale than 0.97?

The 3% reduction (0.97) is the Skills standard for all press feedback. Deviating from this value breaks visual consistency with other interactive elements. If your design system requires adjustment, update skills/review-animations/STANDARDS.md as the single source of truth rather than hardcoding one-off values.

Does this pattern work with server components in Next.js App Router?

The component uses client-side hooks (useSpring, useMotionValue) and must be marked with the "use client" directive. The Skills repository's fallback CSS pattern ensures press feedback remains functional during server rendering or when JavaScript is disabled.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →