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

> React button press spring transition guide. Animate scale on press with Motion for natural, interruptible interactions. Full implementation and example.

- Repository: [Emil Kowalski/skills](https://github.com/emilkowalski/skills)
- Tags: tutorial
- Published: 2026-08-06

---

**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`](https://github.com/emilkowalski/skills/blob/main/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`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md)
- **Consistency** — All interactive elements (modals, drawers, buttons) share the same spring configuration, creating a unified visual language

---

## Recommended Animation Library

The repository's [`skills/pick-ui-library/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/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:

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

```

---

## The Canonical Spring Configuration

Per [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md) (lines 65–70), the **Apple-style spring** is the repository's default for press interactions:

```tsx
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`](https://github.com/emilkowalski/skills/blob/main/skills/emil-design-eng/SKILL.md) that implements the **Skills** button press pattern:

```tsx
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`](https://github.com/emilkowalski/skills/blob/main/skills/pick-ui-library/SKILL.md) | Use the recommended animation library |
| Define `springConfig` object | [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md) | Apply the canonical Apple-style spring values |
| Initialize `scale` with `useSpring(1, springConfig)` | [`skills/emil-design-eng/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/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`](https://github.com/emilkowalski/skills/blob/main/skills/emil-design-eng/SKILL.md) | Apply subtle press feedback (3% reduction) |
| Use `onPointerDown/Up/Leave` | [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/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`](https://github.com/emilkowalski/skills/blob/main/skills/emil-design-eng/SKILL.md). For environments without JavaScript or when Motion fails to load, apply a CSS-based press state:

```css
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`](https://github.com/emilkowalski/skills/blob/main/README.md) | Repository philosophy and skill index |
| [`skills/pick-ui-library/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/pick-ui-library/SKILL.md) | Motion library recommendation |
| [`skills/animate/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/animate/SKILL.md) | Spring configuration theory and timing tables |
| [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md) | Exact spring values (`duration: 0.5, bounce: 0.2`) |
| [`skills/emil-design-eng/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/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`](https://github.com/emilkowalski/skills/blob/main/skills/pick-ui-library/SKILL.md)
- **Spring config**: `{ type: "spring", duration: 0.5, bounce: 0.2 }` from [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/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`](https://github.com/emilkowalski/skills/blob/main/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`](https://github.com/emilkowalski/skills/blob/main/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`](https://github.com/emilkowalski/skills/blob/main/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.