CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-motion

A spring that solves your animation problems.

Pending
Overview
Eval results
Files

motion.mddocs/

Motion Component

The Motion component provides single element animations using spring physics. It's the simplest and most commonly used component in React Motion, ideal for basic state transitions, hover effects, and straightforward UI animations.

Capabilities

Motion Component

Creates a single animated element that transitions between style states using spring physics.

/**
 * Single element animation component using spring physics
 * Animates from defaultStyle (or current style) to target style
 */
class Motion extends React.Component {
  static propTypes = {
    /** Initial style values (optional, defaults to target style values) */
    defaultStyle: PropTypes.objectOf(PropTypes.number),
    /** Target style with spring configurations (required) */
    style: PropTypes.objectOf(PropTypes.oneOfType([
      PropTypes.number,
      PropTypes.object,
    ])).isRequired,
    /** Render function receiving interpolated style values (required) */
    children: PropTypes.func.isRequired,
    /** Callback fired when animation completes (optional) */
    onRest: PropTypes.func,
  };
}

Usage Examples:

import React, { useState } from 'react';
import { Motion, spring } from 'react-motion';

// Basic animation
function BasicMotion() {
  const [open, setOpen] = useState(false);
  
  return (
    <Motion
      defaultStyle={{width: 0, opacity: 0}}
      style={{
        width: spring(open ? 200 : 0),
        opacity: spring(open ? 1 : 0)
      }}
    >
      {({width, opacity}) => (
        <div 
          style={{
            width: `${width}px`,
            opacity,
            background: 'blue',
            overflow: 'hidden'
          }}
        >
          <button onClick={() => setOpen(!open)}>
            Toggle
          </button>
        </div>
      )}
    </Motion>
  );
}

// With custom spring config
function CustomSpringMotion() {
  const [x, setX] = useState(0);
  
  return (
    <Motion
      style={{
        x: spring(x, {stiffness: 120, damping: 17})
      }}
    >
      {({x}) => (
        <div
          style={{transform: `translateX(${x}px)`}}
          onClick={() => setX(x === 0 ? 100 : 0)}
        >
          Click to move
        </div>
      )}
    </Motion>
  );
}

// With onRest callback
function MotionWithCallback() {
  const [scale, setScale] = useState(1);
  const [animating, setAnimating] = useState(false);
  
  return (
    <Motion
      style={{scale: spring(scale)}}
      onRest={() => {
        setAnimating(false);
        console.log('Animation completed!');
      }}
    >
      {({scale}) => (
        <div
          style={{
            transform: `scale(${scale})`,
            transition: animating ? 'none' : undefined
          }}
          onClick={() => {
            setAnimating(true);
            setScale(scale === 1 ? 1.5 : 1);
          }}
        >
          {animating ? 'Animating...' : 'Click to scale'}
        </div>
      )}
    </Motion>
  );
}

defaultStyle Property

Optional initial style values. If not provided, the component will extract initial values from the target style.

/**
 * Initial style values for the animation
 * If omitted, values are extracted from target style
 */
defaultStyle?: PlainStyle;

style Property

Target style object containing numeric values or spring configurations. This is where you define what the animation should transition to.

/**
 * Target style with spring configurations
 * Can mix plain numbers with spring() calls
 */
style: Style;

children Property

Render function that receives the current interpolated style values and returns a React element.

/**
 * Render function receiving interpolated style values
 * Called on every animation frame with current values
 */
children: (interpolatedStyle: PlainStyle) => ReactElement;

onRest Property

Optional callback function fired when the animation reaches its target and stops moving.

/**
 * Callback fired when animation completes
 * Useful for chaining animations or triggering side effects
 */
onRest?: () => void;

Animation Behavior

Spring Physics

The Motion component uses a spring-damper physics system:

  • No duration: Animations run until they naturally settle
  • Interruption-safe: Can be redirected mid-animation without jarring transitions
  • Natural feel: Springs feel more organic than easing curves

Performance

  • Uses requestAnimationFrame for smooth 60fps animations
  • Automatically stops when values reach target within precision threshold
  • Handles browser tab switching gracefully by restarting timing
  • Batches style updates through React's reconciliation

State Management

Internally tracks:

  • currentStyle: Current interpolated values
  • currentVelocity: Current velocity for each animated property
  • lastIdealStyle: Target values from previous frame
  • lastIdealVelocity: Target velocity from previous frame

This state enables smooth interruptions when style prop changes during animation.

Common Patterns

Conditional Animations

<Motion
  style={{
    x: spring(condition ? 100 : 0),
    opacity: spring(visible ? 1 : 0)
  }}
>
  {({x, opacity}) => (
    <div style={{transform: `translateX(${x}px)`, opacity}}>
      Content
    </div>
  )}
</Motion>

Multiple Properties

<Motion
  style={{
    width: spring(expanded ? 200 : 50),
    height: spring(expanded ? 200 : 50),
    rotate: spring(expanded ? 45 : 0),
    borderRadius: spring(expanded ? 20 : 5)
  }}
>
  {({width, height, rotate, borderRadius}) => (
    <div
      style={{
        width: `${width}px`,
        height: `${height}px`,
        transform: `rotate(${rotate}deg)`,
        borderRadius: `${borderRadius}px`
      }}
    >
      Morphing box
    </div>
  )}
</Motion>

Chained Animations

function ChainedAnimation() {
  const [stage, setStage] = useState(0);
  
  return (
    <Motion
      style={{
        x: spring(stage === 0 ? 0 : stage === 1 ? 100 : 200),
        y: spring(stage < 2 ? 0 : 100)
      }}
      onRest={() => {
        if (stage < 2) {
          setStage(stage + 1);
        }
      }}
    >
      {({x, y}) => (
        <div style={{transform: `translate(${x}px, ${y}px)`}}>
          Stage {stage}
        </div>
      )}
    </Motion>
  );
}

Install with Tessl CLI

npx tessl i tessl/npm-react-motion

docs

index.md

motion.md

spring-system.md

staggered-motion.md

transition-motion.md

tile.json