interact.js hands you pointer events and never moves your elements
JavaScript drag and drop, resizing and multi-touch gestures with inertia and snapping for modern browsers (and also IE9+)
At a glance
- What is it?
- interact.js is a TypeScript interaction library for drag, resize and multi-touch with snap and inertia. Its defining constraint is that it does not modify the DOM, so the caller applies every transform by hand, and the README shows only drag, leaving resize and gesture APIs to the docs site.
- Who is it for?
- Adopt interact.js if your interface needs drag, resize or simultaneous multi-touch and you want to own every style change, since the library hands back deltas and leaves rendering to you. Skip it if you want a component that moves elements on its own, or if you are reaching for named gesture events rather than a pointer stream, which is a different kind of library.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 106 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- taye/interact.js12,942 ★ · +27
| Repository | 2026-08-01 | 2026-11-14 |
|---|---|---|
| taye/interact.js | 12.9k | 12.9k |
27 Stars in the last 105 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The library reports movement and leaves the style change to you
The one architectural commitment in the README is stated as a feature: the library does not modify the DOM except to change the cursor, and that cursor change can be disabled. Everything else about the design follows from it. There is no built-in transform, no positioning helper and no virtual drag preview, because applying the move is the caller's job inside a listener. The documented example shows that shape exactly, binding a selector, declaring `.origin('self')` so coordinates are measured against the element itself, and then reading movement values out of the event. A consequence worth stating plainly: adopting interact.js means writing the render step yourself, and a team expecting a drop-in draggable attribute will find there is none. The upside of the same constraint is that intermediate states can be animated, written into SVG attributes or batched into one canvas draw instead of a style write.
Snap is a modifier, and the example stops before inertia or resize
Behaviour is layered through modifiers, and the only one the README shows is snapping, configured as a modifier on a draggable:
var pixelSize = 16;
interact('.rainbow-pixel-canvas')
.origin('self')
.draggable({
modifiers: [
interact.modifiers.snap({
// snap to the corners of a grid
targets: [
interact.snappers.grid({ x: pixelSize, y: pixelSize }),
],
})
],
listeners: {
// draw colored squares on move
move: function (event) {The grid snapper takes both axes as one object, so a uniform grid is a single number pair. Below that listener the example reads `event.dx` and `event.dy` and converts them into a drag angle, which is the clearest evidence that the event carries raw movement rather than a resolved result. Inertia and snapping are both listed as features, but no inertia modifier call appears anywhere in the README, and neither the resize nor the multi-touch API is shown. The single worked example covers drag alone, so anything else has to be looked up at the docs site.
Five install paths, three of which hand you a global script
Installation is offered five ways, and they differ in what they hand your build:
npm install interactjs
yarn add interactjs
//= require interactjs/interact
libraryDependencies ++= Seq("org.webjars.npm" % "interactjs" % version)The last two lines belong to the Rails 5.1 and up path and the Webjars path for SBT and Play 2. The Rails pairing is a package install followed by a Sprockets require directive. The two CDN entries, jsDelivr and unpkg, both point at `dist/interact.min.js` through a script tag, which puts the library on the page as a global instead of a module import. Pick the npm route if you want module resolution and type resolution to agree, and one of the CDN routes only if you have no bundler at all. Note that the SBT snippet ends in a bare `version` variable that the build has to define, so copying it as-is will not compile. One wrinkle sits next to all of this: the source is TypeScript and the npm package already carries its type definitions, yet a standalone typings package also exists for `npm install --save-dev @interactjs/types`. That one is for when you want the declarations without the runtime.
The root package.json is a private workspace, so its version is not the shipped one
The manifest at the repository root is named `@interactjs/_dev`, marked private, version 1.10.28, with an empty description field and a homepage pointing at the pro site rather than the project docs. A `lerna.json` and a `packages/` directory sit next to it, so this is a workspace root rather than the manifest of the artifact you install. The package you actually pull is `interactjs`. The consequence for anyone tracking versions is that the number at the root belongs to the development workspace, and this repository publishes no GitHub releases, so there is no release list on the repository page to compare it against. Version history lives in `CHANGELOG.md` and on the package registry instead.
prepare runs bin/_link and husky install, so a fresh install rewrites the checkout
The root manifest wires local tooling into the install lifecycle. The bootstrap script is:
yarn install --pure-lockfile --prefer-offline --silent && sh bin/_linkand the prepare script is declared as `bin/_link; husky install`, so linking local packages and registering git hooks both happen as a side effect of installing. The build pipeline uses the same convention with underscore-prefixed helpers: `start` and `build:esnext` both call `_add_plugin_indexes`, `build:types` calls `_types`, and `tsc_lint_test` chains `_add_plugin_indexes`, `tsc -b -f`, `_lint` and the test run. Those helpers are not defined in the manifest's scripts block, so they resolve from the `bin/` directory or from a workspace package. For anyone who only intends to consume the library this is invisible, but in a fork, installing dependencies mutates the working tree and installs hooks.
The README defines an upcoming-changes link no visible sentence uses
At the bottom of the README there is a link reference pointing at the `upcoming-changes` section of `CHANGELOG.md` on the main branch. No visible sentence in the document attaches text to it. Whatever the author intended to say about what is about to change is therefore only visible by opening the changelog and scrolling to that anchor. The README states no deprecation timeline, no supported-versions table and no semver policy, and it does not say which release a breaking change would land in. That silence is the practical risk for a library this old in browser API terms: you cannot tell from the README whether a version you are about to pin has a known migration waiting. Read the changelog section before upgrading a pinned dependency.
IE9 support is a sentence, not a per-feature support matrix
Compatibility is stated as a list: the desktop and mobile versions of Chrome, Firefox and Opera, plus Internet Explorer 9 and up, with SVG interaction named as supported. The repository carries a `.browserslistrc` and a Babel setup with `@babel/preset-env` and several transform plugins, which is how a modern build reaches those targets. What the documentation does not offer is a matrix saying which parts of the API degrade and where. The `examples/` directory is the closest thing to a feature inventory: dropzones, events, iframes, snap, sortable, star, svg-editor and transform. Sortable lists and drop targets exist as demos, which says more about the library's scope than the README does, but it does not say whether they behave identically on Internet Explorer 9. The last push on this repository was on 2026-08-01, and it is not archived. The licence is MIT.
interact.js streams pointers where a gesture recogniser emits gestures
A common comparison is interact.js against Hammer.js, and the difference is one of abstraction level rather than quality. A gesture recogniser takes raw input, works out what the user is doing, and fires named gesture events such as a tap, a swipe or a pinch. interact.js does not classify anything: it delivers movement deltas, keeps modifier logic in the caller's hands and treats snapping and inertia as things you compose onto a drag rather than outcomes it reports. That design is what lets the same pointer stream drive a canvas grid snapper or an SVG attribute update. If your requirement is a single recognisable gesture on a touch surface, a recogniser-shaped library asks less of you. If your requirement is a custom manipulation that no named gesture covers, the modifier pipeline is the part you would end up rebuilding on top of a recogniser anyway.
Editorial conclusion
Adopt interact.js if your interface needs drag, resize or simultaneous multi-touch and you want to own every style change, since the library hands back deltas and leaves rendering to you. Skip it if you want a component that moves elements on its own, or if you are reaching for named gesture events rather than a pointer stream, which is a different kind of library. Check the CHANGELOG at main before you pin a version: the README links to an upcoming-changes section but states no breaking-change policy, and the repository has no GitHub releases to diff against.
Frequently asked questions
What is interact js?
It is a TypeScript library for drag and drop, resizing and multi-touch gestures with inertia and snapping, published to npm as interactjs. It does not modify the DOM apart from a cursor change that can be disabled, so the caller applies every style update.
interact js vs hammerjs
Hammer.js is a gesture recogniser that classifies input into named gestures such as tap, swipe and pinch. interact.js does not classify: it hands back movement deltas and lets the caller compose snapping and inertia as modifiers, so the same stream can drive canvas, SVG or DOM updates.
How do I install interact.js and its TypeScript types?
Run `npm install interactjs`, or load `dist/interact.min.js` from jsDelivr or unpkg with a script tag. The package already contains its type definitions; `npm install --save-dev @interactjs/types` is for when you need the typings on their own.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/taye-interact-js)Star history chart for your README
[](https://hysenlabs.com/projects/taye-interact-js)Was this useful?