How to Implement Spring Animations with Apple-Style Config in React

Use the Motion library (formerly Framer Motion) with the configuration object { type: "spring", duration: 0.5, bounce: 0.2 } to create natural, interruptible animations that carry velocity through gestures and retarget smoothly without abrupt resets.

According to the emilkowalski/skills repository, spring-based motion is the preferred method for animating UI that reacts to user gestures like drag, swipe, and tap-and-hold. The repository defines a specific Apple-style spring configuration that balances perceptual settling time with subtle overshoot, ensuring interface elements feel responsive yet polished.

Understanding the Apple-Style Spring Configuration

The canonical Apple-style spring configuration defined in skills/review-animations/STANDARDS.md uses a simple three-parameter object:

{ type: "spring", duration: 0.5, bounce: 0.2 }

The Physics Parameters

  • duration (0.5s): Controls the perceptual time until the spring visually settles. This is not a hard timeout but rather the characteristic timescale of the decay.
  • bounce (0.2): Governs the overshoot amount. A value of 0.2 provides a subtle, lively motion without distracting the user. According to the audit guidelines in skills/improve-animations/AUDIT.md, keep bounce between 0.1 and 0.3 for most UI, reserving higher values (≈0.3) only for playful interactions like drag-to-dismiss.

When to Use Spring Animations

Spring physics excel in gesture-driven, interruptible UI contexts where elements must maintain momentum. As documented in skills/apple-design/SKILL.md, springs retain velocity and can be retargeted mid-animation without the "brick-wall" reset effect common in CSS keyframe animations.

Use springs for:

  • Drag-to-dismiss modals and sheets
  • Pull-up interactions
  • Toggle switches that can be quickly reversed
  • Any animation that might be interrupted by subsequent user input

Avoid springs for:

  • Simple opacity fades or color transitions (use CSS transitions)
  • Non-interruptible sequential animations
  • Background loops where physics continuity is irrelevant

Implementing Springs with Motion

The skills/pick-ui-library/SKILL.md file explicitly recommends Motion as the go-to library because it exposes the exact { type, duration, bounce } API that maps directly to the Apple-style configuration.

Basic Implementation

Import the animate function and pass the Apple-style config as the third argument:

import { animate } from "motion";

function SlidingPanel({ isOpen }) {
  const yTarget = isOpen ? 0 : 100;

  animate(
    ".panel",
    { y: yTarget },
    { type: "spring", duration: 0.5, bounce: 0.2 }
  );

  return <div className="panel">Content</div>;
}

This implementation mirrors the example found in skills/review-animations/STANDARDS.md at lines 65-68, providing a 0.5-second perceptual duration with 20% bounce.

Handling Gesture Velocity

For draggable interfaces, you must pass the release velocity to the spring to ensure natural momentum continuation. The skills/apple-design/SKILL.md file (lines 104-110) emphasizes normalizing velocity when the API expects a fraction of the remaining distance.

import { useSpring, motion } from "motion";
import { useState } from "react";

export default function DraggableCard() {
  const [dragging, setDragging] = useState(false);
  const x = useSpring(0, { type: "spring", duration: 0.5, bounce: 0.2 });

  return (
    <motion.div
      style={{ x }}
      drag="x"
      dragMomentum={false}
      onDragStart={() => setDragging(true)}
      onDragEnd={(event, info) => {
        setDragging(false);
        // Pass release velocity (px/s) back into the spring
        x.set(info.velocity.x, { velocity: info.velocity.x });
      }}
    />
  );
}

The info.velocity.x value carries the gesture's momentum into the spring physics, creating a seamless transition from user control to automated animation.

Centralizing Configuration Constants

To ensure consistency across your codebase, define the Apple-style spring as a constant:

// src/constants/animation.js
export const APPLE_SPRING = { type: "spring", duration: 0.5, bounce: 0.2 };
import { animate } from "motion";
import { APPLE_SPRING } from "./constants/animation";

animate(element, { opacity: 1, scale: 1 }, APPLE_SPRING);

This pattern, referenced in skills/emil-design-eng/SKILL.md, makes global adjustments trivial—changing the bounce value in one place updates every animation using the constant.

Accessibility Considerations

Spring animations must respect user motion preferences. Wrap spring-based components in @media (prefers-reduced-motion: reduce) queries as specified in skills/apple-design/SKILL.md (lines 203-207).

Replace springs with simple opacity cross-fades or static state changes when reduced motion is requested:

@media (prefers-reduced-motion: reduce) {
  .spring-animated {
    transition: opacity 0.1s linear;
    /* Disable spring physics */
    transition-timing-function: linear;
  }
}

This ensures compliance with accessibility standards while preserving the enhanced experience for users who prefer motion.

Summary

  • Use Motion (formerly Framer Motion) to implement Apple-style springs in React, as it natively supports the { type: "spring", duration: 0.5, bounce: 0.2 } API.
  • Reference skills/review-animations/STANDARDS.md for the canonical configuration defaults and physics rationale.
  • Preserve gesture velocity by passing release velocity to the spring's velocity option, ensuring natural momentum as documented in skills/apple-design/SKILL.md.
  • Centralize configs in constants files to maintain consistency and simplify global tweaks.
  • Support reduced motion by disabling spring physics for users with motion sensitivity preferences.

Frequently Asked Questions

What library does the emilkowalski/skills repository recommend for spring animations?

According to skills/pick-ui-library/SKILL.md, the repository recommends Motion (formerly Framer Motion) because it exposes a { type, duration, bounce } API that maps directly to the Apple-style configuration without requiring manual physics calculations.

How do I handle bounce values for different types of interactions?

Keep bounce subtle at 0.2 for standard UI elements like toggles and sheets to avoid visual noise. Reserve higher bounce values around 0.3 only for playful, bouncy interactions such as drag-to-dismiss gestures, as advised in the audit guidelines at skills/improve-animations/AUDIT.md.

Why should I use springs instead of CSS transitions for gesture-based animations?

Springs carry velocity through interruptions and can be retargeted smoothly, whereas CSS keyframes create a "brick-wall" reset effect when interrupted. This behavior is critical for drag gestures and any UI that might receive rapid, successive inputs.

How do I make spring animations accessible?

Wrap spring-based components in @media (prefers-reduced-motion: reduce) media queries and replace spring physics with simple opacity cross-fades or instant state changes. The skills/apple-design/SKILL.md file explicitly requires this pattern at lines 203-207 for accessibility compliance.

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 →