How to Drag Matter.js Bodies with Touch

Capturing user touch gestures to drag physics bodies in Matter.js requires integrating the Matter.Mouse and Matter.MouseConstraint modules with your rendering canvas. While Matter.js includes built-in touch listeners within its mouse module, mobile browsers often intercept these gestures for scrolling, zooming, or panning. This guide covers how to set up touch-based interaction, sync coordinates accurately, and prevent mobile browser gesture conflicts.

1. Create the Mouse and MouseConstraint

Matter.js treats mouse and touch inputs through the same abstraction layer (Matter.Mouse). When you bind a mouse instance to a canvas element, it automatically attaches both pointer/mouse event listeners (mousedown, mousemove, mouseup) and touch event listeners (touchstart, touchmove, touchend).

// Setup engine and renderer
const engine = Matter.Engine.create();
const render = Matter.Render.create({
  element: document.body,
  engine: engine,
  canvas: document.getElementById('world'),
  options: {
    width: window.innerWidth,
    height: window.innerHeight,
    wireframes: false
  }
});

// 1. Create the Mouse instance linked to the canvas
const mouse = Matter.Mouse.create(render.canvas);

// 2. Create the MouseConstraint
const mouseConstraint = Matter.MouseConstraint.create(engine, {
  mouse: mouse,
  constraint: {
    stiffness: 0.2,
    render: {
      visible: false
    }
  }
});

// 3. Add the constraint to the world
Matter.Composite.add(engine.world, mouseConstraint);

// 4. Keep the mouse in sync with rendering
render.mouse = mouse;

2. Disable Default Touch Actions via CSS

The most common reason touch dragging fails on mobile screens is that the browser captures the gesture for viewport scrolling before Matter.js can process it. You must disable standard touch behaviors on the canvas element.

Apply the touch-action CSS property directly to your canvas:

canvas {
  touch-action: none;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

Setting touch-action: none informs the browser that all touch interactions inside the canvas should be handled exclusively by JavaScript, preventing default scroll and pinch-to-zoom behaviors.

3. Account for Device Pixel Ratio and Scaling

On high-density mobile screens (Retina displays), mismatching dimensions between the canvas style width and its internal drawing buffer will misalign touch coordinates relative to the physics bodies.

Ensure your mouse pixel ratio matches the renderer:

// Adjust for mobile device pixel ratios
const pixelRatio = window.devicePixelRatio || 1;

mouse.pixelRatio = pixelRatio;

If you dynamically resize the canvas or scale the viewport, call Matter.Mouse.setScale or update mouse.pixelRatio so that touch points accurately map to body boundaries.

4. Prevent Page Scroll via Event Listeners (Fallback)

If legacy mobile browsers continue to scroll during touch interactions, explicitly prevent default behavior on the canvas touch events:

const canvas = render.canvas;

canvas.addEventListener('touchstart', (e) => {
  e.preventDefault();
}, { passive: false });

canvas.addEventListener('touchmove', (e) => {
  e.preventDefault();
}, { passive: false });

Setting { passive: false } is required in modern browsers to allow e.preventDefault() to stop viewport movement.