CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-framer-motion

A production-ready motion library for React that provides comprehensive animation and gesture APIs for creating fluid, performant interactions.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

gestures.mddocs/

Gestures

Drag controls and gesture event handlers for interactive animations and user input handling.

Capabilities

Drag Controls Hook

Creates controls for programmatically managing drag operations.

/**
 * Creates drag controls for manual drag management
 * @returns DragControls instance
 */
function useDragControls(): DragControls;

interface DragControls {
  /**
   * Start a drag operation
   * @param event - Pointer event that triggered the drag
   * @param options - Drag start options
   */
  start(event: React.PointerEvent | PointerEvent, options?: StartOptions): void;
  
  /**
   * Cancel the current drag operation
   */
  cancel(): void;
  
  /**
   * Stop the current drag operation
   */
  stop(): void;
  
  /**
   * Subscribe to drag controls updates
   * @param controls - Another drag controls instance to link
   */
  subscribe(controls: DragControls): () => void;
}

interface StartOptions {
  /**
   * Snap back to original position when drag ends
   */
  snapToCursor?: boolean;
  
  /**
   * Cursor to use during drag
   */
  cursorProgress?: Point;
}

interface Point {
  x: number;
  y: number;
}

Usage Examples:

import { motion, useDragControls } from "framer-motion";
import { useRef } from "react";

// Basic drag controls
function DragControlsExample() {
  const controls = useDragControls();
  
  return (
    <div>
      <div
        className="w-8 h-8 bg-blue-500 cursor-grab rounded-full mb-4"
        onPointerDown={(e) => controls.start(e)}
      >
        Drag Handle
      </div>
      
      <motion.div
        drag
        dragControls={controls}
        className="w-24 h-24 bg-red-500 rounded"
      >
        Draggable Element
      </motion.div>
    </div>
  );
}

// Multiple linked drag controls
function LinkedDragExample() {
  const controls1 = useDragControls();
  const controls2 = useDragControls();
  
  // Link controls so they move together
  React.useEffect(() => {
    const unsubscribe = controls1.subscribe(controls2);
    return unsubscribe;
  }, [controls1, controls2]);
  
  return (
    <div className="space-y-4">
      <motion.div
        drag
        dragControls={controls1}
        className="w-24 h-24 bg-blue-500 rounded"
      >
        Element 1
      </motion.div>
      
      <motion.div
        drag
        dragControls={controls2}
        className="w-24 h-24 bg-green-500 rounded"
      >
        Element 2 (linked)
      </motion.div>
    </div>
  );
}

Drag Props and Events

Motion components support comprehensive drag functionality through props.

interface DragProps {
  /**
   * Enable dragging on x, y, or both axes
   */
  drag?: boolean | "x" | "y";
  
  /**
   * Drag controls instance for manual control
   */
  dragControls?: DragControls;
  
  /**
   * Constraints for drag boundaries
   */
  dragConstraints?: Partial<BoundingBox2D> | React.RefObject<Element>;
  
  /**
   * Enable elastic drag beyond constraints
   */
  dragElastic?: boolean | number;
  
  /**
   * Enable momentum and inertia after drag ends
   */
  dragMomentum?: boolean;
  
  /**
   * Transition for snapping back to constraints
   */
  dragTransition?: {
    bounceStiffness?: number;
    bounceDamping?: number;
    power?: number;
    timeConstant?: number;
    restDelta?: number;
    modifyTarget?: (target: number) => number;
  };
  
  /**
   * Propagate drag to parent elements
   */
  dragPropagation?: boolean;
  
  /**
   * Listen for external drag events
   */
  dragListener?: boolean;
  
  /**
   * Direction lock threshold
   */
  dragDirectionLock?: boolean;
  
  /**
   * Minimum distance before drag starts
   */
  dragSnapToOrigin?: boolean;
}

interface BoundingBox2D {
  top: number;
  right: number;
  bottom: number;
  left: number;
}

Drag Event Handlers:

interface DragEventHandlers {
  /**
   * Called when drag operation starts
   */
  onDragStart?: (
    event: MouseEvent | TouchEvent | PointerEvent,
    info: PanInfo
  ) => void;
  
  /**
   * Called continuously during drag
   */
  onDrag?: (
    event: MouseEvent | TouchEvent | PointerEvent,
    info: PanInfo
  ) => void;
  
  /**
   * Called when drag operation ends
   */
  onDragEnd?: (
    event: MouseEvent | TouchEvent | PointerEvent,
    info: PanInfo
  ) => void;
  
  /**
   * Called when dragging beyond constraints (elastic)
   */
  onDirectionLock?: (axis: "x" | "y") => void;
}

interface PanInfo {
  /**
   * Current pointer position relative to page
   */
  point: Point;
  
  /**
   * Change in position since last event
   */
  delta: Point;
  
  /**
   * Total offset from drag start position
   */
  offset: Point;
  
  /**
   * Current velocity of the pointer
   */
  velocity: Point;
}

Usage Examples:

import { motion } from "framer-motion";
import { useRef, useState } from "react";

// Constrained dragging
function ConstrainedDragExample() {
  const constraintsRef = useRef<HTMLDivElement>(null);
  
  return (
    <div
      ref={constraintsRef}
      className="w-96 h-96 bg-gray-200 relative border-2 border-gray-400"
    >
      <motion.div
        drag
        dragConstraints={constraintsRef}
        dragElastic={0.2}
        className="w-16 h-16 bg-blue-500 rounded cursor-grab"
      >
        Constrained
      </motion.div>
    </div>
  );
}

// Axis-specific dragging with momentum
function AxisDragExample() {
  return (
    <div className="space-y-8">
      <motion.div
        drag="x"
        dragMomentum={true}
        dragConstraints={{ left: 0, right: 300 }}
        className="w-16 h-16 bg-red-500 rounded cursor-grab"
      >
        X-axis only
      </motion.div>
      
      <motion.div
        drag="y"
        dragMomentum={false}
        dragConstraints={{ top: 0, bottom: 200 }}
        className="w-16 h-16 bg-green-500 rounded cursor-grab"
      >
        Y-axis only
      </motion.div>
    </div>
  );
}

// Drag with custom transitions and events
function AdvancedDragExample() {
  const [dragInfo, setDragInfo] = useState<PanInfo | null>(null);
  
  return (
    <div>
      <motion.div
        drag
        dragConstraints={{ left: -200, right: 200, top: -200, bottom: 200 }}
        dragTransition={{
          bounceStiffness: 300,
          bounceDamping: 20,
          power: 0.2,
          modifyTarget: (target) => Math.round(target / 50) * 50 // Snap to grid
        }}
        onDragStart={(event, info) => {
          console.log("Drag started", info);
        }}
        onDrag={(event, info) => {
          setDragInfo(info);
        }}
        onDragEnd={(event, info) => {
          console.log("Drag ended", info);
          setDragInfo(null);
        }}
        className="w-16 h-16 bg-purple-500 rounded cursor-grab"
      >
        Advanced Drag
      </motion.div>
      
      {dragInfo && (
        <div className="mt-4 text-sm">
          <p>Position: {Math.round(dragInfo.point.x)}, {Math.round(dragInfo.point.y)}</p>
          <p>Velocity: {Math.round(dragInfo.velocity.x)}, {Math.round(dragInfo.velocity.y)}</p>
          <p>Offset: {Math.round(dragInfo.offset.x)}, {Math.round(dragInfo.offset.y)}</p>
        </div>
      )}
    </div>
  );
}

Hover Events

Handle mouse hover interactions with motion components.

interface HoverEventHandlers {
  /**
   * Called when mouse enters element
   */
  onHoverStart?: (event: MouseEvent, info: EventInfo) => void;
  
  /**
   * Called when mouse leaves element
   */
  onHoverEnd?: (event: MouseEvent, info: EventInfo) => void;
}

interface EventInfo {
  /**
   * Current pointer position
   */
  point: Point;
}

Usage Example:

import { motion } from "framer-motion";
import { useState } from "react";

function HoverExample() {
  const [hoverInfo, setHoverInfo] = useState<string>("");
  
  return (
    <motion.div
      whileHover={{ scale: 1.1, rotate: 5 }}
      onHoverStart={(event, info) => {
        setHoverInfo(`Hover started at ${info.point.x}, ${info.point.y}`);
      }}
      onHoverEnd={(event, info) => {
        setHoverInfo(`Hover ended at ${info.point.x}, ${info.point.y}`);
      }}
      className="w-32 h-32 bg-blue-500 rounded cursor-pointer flex items-center justify-center text-white"
    >
      Hover me
      {hoverInfo && <div className="absolute top-full mt-2 text-sm text-black">{hoverInfo}</div>}
    </motion.div>
  );
}

Tap Events

Handle tap/click interactions with detailed gesture information.

interface TapEventHandlers {
  /**
   * Called when tap/click occurs
   */
  onTap?: (event: MouseEvent | TouchEvent | PointerEvent, info: TapInfo) => void;
  
  /**
   * Called when tap/click starts (pointer down)
   */
  onTapStart?: (event: MouseEvent | TouchEvent | PointerEvent, info: TapInfo) => void;
  
  /**
   * Called when tap is cancelled (pointer moved too far)
   */
  onTapCancel?: (event: MouseEvent | TouchEvent | PointerEvent, info: TapInfo) => void;
}

interface TapInfo {
  /**
   * Current pointer position
   */
  point: Point;
}

Usage Example:

import { motion } from "framer-motion";
import { useState } from "react";

function TapExample() {
  const [tapCount, setTapCount] = useState(0);
  const [lastTapPoint, setLastTapPoint] = useState<Point | null>(null);
  
  return (
    <motion.button
      whileTap={{ scale: 0.95 }}
      onTap={(event, info) => {
        setTapCount(count => count + 1);
        setLastTapPoint(info.point);
      }}
      onTapStart={(event, info) => {
        console.log("Tap started at", info.point);
      }}
      onTapCancel={(event, info) => {
        console.log("Tap cancelled at", info.point);
      }}
      className="px-6 py-3 bg-green-500 text-white rounded hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-green-400"
    >
      Tap me (count: {tapCount})
      {lastTapPoint && (
        <div className="text-xs mt-1">
          Last tap: {Math.round(lastTapPoint.x)}, {Math.round(lastTapPoint.y)}
        </div>
      )}
    </motion.button>
  );
}

Focus Events

Handle focus and blur events for accessibility and keyboard navigation.

interface FocusEventHandlers {
  /**
   * Called when element receives focus
   */
  onFocus?: (event: FocusEvent) => void;
  
  /**
   * Called when element loses focus
   */
  onBlur?: (event: FocusEvent) => void;
}

Usage Example:

import { motion } from "framer-motion";
import { useState } from "react";

function FocusExample() {
  const [isFocused, setIsFocused] = useState(false);
  
  return (
    <motion.input
      type="text"
      placeholder="Focus me"
      whileFocus={{ scale: 1.05, borderColor: "#3B82F6" }}
      onFocus={() => setIsFocused(true)}
      onBlur={() => setIsFocused(false)}
      className="px-4 py-2 border-2 border-gray-300 rounded outline-none transition-colors"
      style={{
        borderColor: isFocused ? "#3B82F6" : "#D1D5DB"
      }}
    />
  );
}

DOM Event Utilities

Utilities for handling DOM events in a cross-platform way.

/**
 * Add pointer event listener with proper cross-platform handling
 * @param element - Element to add listener to
 * @param event - Event type to listen for
 * @param handler - Event handler function
 * @param options - Event listener options
 * @returns Cleanup function
 */
function addPointerEvent(
  element: Element,
  event: string,
  handler: (event: PointerEvent) => void,
  options?: AddEventListenerOptions
): () => void;

/**
 * Add pointer info to event handlers for consistent data structure
 * @param handler - Original event handler
 * @returns Enhanced handler with pointer info
 */
function addPointerInfo<T extends Event>(
  handler: (event: T, info: EventInfo) => void
): (event: T) => void;

/**
 * React hook for DOM event handling
 * @param ref - Element reference
 * @param event - Event type
 * @param handler - Event handler
 * @param options - Event options
 */
function useDomEvent(
  ref: React.RefObject<Element>,
  event: string,
  handler: (event: Event) => void,
  options?: AddEventListenerOptions
): void;

Usage Example:

import { useDomEvent } from "framer-motion";
import { useRef, useEffect } from "react";

function DOMEventExample() {
  const ref = useRef<HTMLDivElement>(null);
  
  // React hook approach
  useDomEvent(ref, "pointerdown", (event) => {
    console.log("Pointer down:", event);
  });
  
  // Manual approach
  useEffect(() => {
    const element = ref.current;
    if (!element) return;
    
    const cleanup = addPointerEvent(
      element,
      "pointermove",
      (event) => {
        console.log("Pointer move:", event.clientX, event.clientY);
      },
      { passive: true }
    );
    
    return cleanup;
  }, []);
  
  return (
    <div
      ref={ref}
      className="w-64 h-64 bg-gray-200 border-2 border-gray-400 flex items-center justify-center"
    >
      Interactive area
    </div>
  );
}

Gesture Combination Patterns

Drag with Hover:

<motion.div
  drag
  whileHover={{ scale: 1.05 }}
  whileDrag={{ scale: 1.1, zIndex: 10 }}
  onDragStart={() => console.log("Started dragging")}
  onHoverStart={() => console.log("Started hovering")}
>
  Combined gestures
</motion.div>

Conditional Gestures:

const [isDraggable, setIsDraggable] = useState(true);

<motion.div
  drag={isDraggable}
  dragConstraints={isDraggable ? { left: 0, right: 300 } : false}
  whileTap={!isDraggable ? { scale: 0.95 } : undefined}
  onTap={() => {
    if (!isDraggable) {
      console.log("Clicked instead of dragged");
    }
  }}
>
  Conditional interaction
</motion.div>

Multi-Touch Support:

<motion.div
  drag
  onPanStart={(event, info) => {
    // Handle touch/pan start
    console.log("Pan started with", info.point);
  }}
  onPan={(event, info) => {
    // Handle continuous touch/pan
    console.log("Panning:", info.delta);
  }}
  onPanEnd={(event, info) => {
    // Handle touch/pan end
    console.log("Pan ended with velocity:", info.velocity);
  }}
>
  Multi-touch support
</motion.div>

docs

animation-controls.md

configuration.md

dom-utilities.md

gestures.md

index.md

layout-presence.md

motion-components.md

motion-values.md

scroll-view.md

tile.json