Sync HTML Elements with Matter.js Using DOM Plugin

This article explains how to use matter-dom-plugin to bind standard HTML elements to Matter.js physics bodies. By replacing or augmenting the default HTML5 Canvas renderer with DOM-based rendering, you can apply real-time 2D physics—including gravity, collisions, and friction—directly to text boxes, images, buttons, and custom layout components using CSS transforms.

What is matter-dom-plugin?

Matter.js typically renders physics simulations to an HTML5 <canvas> element using its built-in Matter.Render module. The matter-dom-plugin extends Matter.js so that each physical body's position (x, y) and rotation angle (angle) automatically map to the CSS transform properties (translate3d and rotate) of a designated DOM node. This allows standard web elements to inherit realistic physical movement while retaining interactive features such as clickable links, selectable text, and CSS styling.

Installation and Setup

To get started, install both Matter.js and the DOM plugin via npm or include them via a script tag.

Using npm:

npm install matter-js matter-dom-plugin

Using standard script imports:

<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js"></script>
<script src="path/to/matter-dom-plugin.js"></script>

Initializing the Plugin

Register the plugin with Matter.js before creating your engine and world.

import Matter from 'matter-js';
import MatterDomPlugin from 'matter-dom-plugin';

// Register the plugin with Matter.js
Matter.use(MatterDomPlugin);

If you are using script tags in a browser environment, the plugin typically auto-registers itself with the global Matter object.

HTML and CSS Configuration

Prepare your container and the elements you wish to simulate. The container must have absolute or relative positioning, and the physics elements must have absolute positioning so transforms calculate correctly from the container's top-left origin.

<div id="viewport" style="position: relative; width: 800px; height: 600px; overflow: hidden; border: 1px solid #ccc;">
  <div id="box" style="position: absolute; width: 100px; height: 100px; background-color: #ff5722;">
    Interactive Box
  </div>
</div>

Ensure transform-origin on the DOM elements is set to center center to align with the center-of-mass coordinates used by Matter.js bodies:

#box {
  transform-origin: center center;
  top: 0;
  left: 0;
  margin-top: -50px; /* Half of height */
  margin-left: -50px; /* Half of width */
}

Creating Bodies and Linking DOM Elements

To bind an element, pass the DOM node reference inside the body options under the dom property.

const { Engine, Runner, Bodies, Composite } = Matter;

// Create engine
const engine = Engine.create();
const world = engine.world;

// Select DOM element
const domElement = document.getElementById('box');

// Create a physical body matching the element's size and link the DOM element
const boxBody = Bodies.rectangle(400, 100, 100, 100, {
  restitution: 0.8,
  dom: {
    element: domElement
  }
});

// Create static boundaries to keep the body inside the viewport
const ground = Bodies.rectangle(400, 590, 810, 20, { isStatic: true });
const leftWall = Bodies.rectangle(0, 300, 20, 600, { isStatic: true });
const rightWall = Bodies.rectangle(800, 300, 20, 600, { isStatic: true });

// Add bodies to the world
Composite.add(world, [boxBody, ground, leftWall, rightWall]);

Running the Simulation

Initialize the DomRender provided by the plugin (or the standard runner loop configured for DOM updates) to synchronize physics states with the DOM tree on every frame.

const { DomRender, Runner } = Matter;

// Initialize the DOM renderer
const domRender = DomRender.create({
  engine: engine,
  container: document.getElementById('viewport')
});

// Run renderer and engine
DomRender.run(domRender);
const runner = Runner.create();
Runner.run(runner, engine);

Handling Interactions

Once integrated, DOM nodes support standard event listeners without interrupting the physics engine. You can attach native mouse listeners or apply Matter.js constraints, such as Matter.MouseConstraint, to drag and toss DOM elements across the viewport.