An hour for the PR, a month for the details
Ignite UI for Angular 22.1.0 no longer depends on HammerJS. The library had used it for touch gestures since early 2018. The pull request that removed it, #17359, merged on July 28, 2026: 30 commits, 40 files, 790 lines out and 655 in.
I did this work with Claude. The first pass came from Claude Opus 4.8, the latest Opus at the time, running as a GitHub Copilot coding agent. It produced a complete PR with passing tests in a little over an hour.
Making it behave on real phones took the next month. This post covers why HammerJS had to go, what the first pass got right, and what only testing by hand could catch.
Why HammerJS had to go
Angular itself pulled the rug. The framework deprecated its HammerJS integration in Angular 20, and HammerModule is gone from @angular/platform-browser in Angular 22. In our 22.0.0 release, touch gestures therefore needed a manual step: install hammerjs and add its script to angular.json yourself.
The library was also stale. HammerJS’s last release, 2.0.8, is about a decade old, and it wraps browser APIs that every modern browser now ships natively as Pointer Events. An unmaintained package in every customer’s lockfile is a recurring item in security audits.
The third reason was zoneless Angular. Ignite UI for Angular 22.1 dropped its dependency on NgZone, and the old Hammer-based gesture manager was built around it. Removing HammerJS was the last step of a path that started in 2024, when we made it optional (#13905).
What it touched
Five components used Hammer gestures, and each moved onto native browser events. Four of them now share one new class, IgxTouchManager, in igniteui-angular/core.
| Component | Hammer gestures before | Native replacement |
|---|---|---|
| Carousel | tap, pan in four directions, pan end | IgxTouchManager with velocity-based swipe |
| Navigation Drawer | swipe and pan, listened on the document | IgxTouchManager on the document, touch input only |
| List Item | pan start, move, end and cancel | IgxTouchManager with pointer capture |
| Time Picker columns | vertical pan to scroll values | IgxTouchManager with a distance threshold |
| Grid cells | double-tap on iOS | the browser’s own dblclick |
IgxTouchManager is a small, zoneless gesture recognizer built on Pointer Events. Consumers pass callbacks (panStart, panMove, panEnd, panCancel, tap, swipe) and get back deltas, distance, velocity and the gesture’s center point.
The plumbing went too. The Hammer types left the public exports, and the ng add schematic stopped offering to install HammerJS. Eight Karma configs, angular.json polyfills, two test tsconfigs and every package.json lost their Hammer entries. Gesture tests now dispatch real PointerEvents instead of using hammer-simulator.
The first pass: Claude Opus 4.8
The work started from issue #17358, handed to the Copilot coding agent running Claude Opus 4.8. Ten minutes after posting its plan, it pushed a commit that migrated all five components and stripped Hammer from the build. Thirteen minutes later it had updated the tests and the changelog.
The first draft was not how I wanted it built. It injected NgZone into every component, in a library that had to be zoneless, and it copied the same pan and swipe logic into four files. I asked for a zoneless, shared gesture manager instead.
Thirty-seven minutes later, IgxTouchManager existed, NgZone was gone from the gesture code, and every affected suite passed: list 40 of 40, carousel 45 of 45, time picker 58 of 58, navigation drawer 36 of 36. The PR description was accurate enough that I pointed our tester to it as the migration summary.
For a cross-cutting change like this, that is real leverage. The mechanical work, finding every reference across components, configs, schematics and specs, was done within the hour.
What only a real device could catch
Green tests turned out to prove very little. The specs dispatched synthetic events, while the bugs lived in how real browsers treat a finger on glass. Over the next month, device testing and code review turned up these problems, each fixed by hand.
| Where | What we saw | Why | Fix |
|---|---|---|---|
| Navigation Drawer | Swiping it open showed only a sliver of border, not the panel | Its width variable is forced to 0 while closed, and the size measurement inherited that 0 | Pin the real width during the pan; reset the sizing variables on the measuring element |
| Navigation Drawer | An edge swipe scrolled or bounced the page instead of opening the drawer | The browser cancels pointer events and takes over the touch for scrolling | Block default touchmove only while a gesture is tracked; handle pointercancel; detach listeners when pinned |
| Time Picker | A long drag moved only one value, or scrolled the page | No touch-action: none, and the logic stepped only when the drag changed direction |
Add touch-action: none; step one value every 25 px of travel |
| Carousel | Tapping slide content no longer paused autoplay | Pointer capture retargets events to the host element | Record the element the gesture started on; match any element inside a slide |
| List Item | The pan-start event fired on plain taps | The new manager signalled pan start on press; Hammer waited for movement | Fire pan start only after real movement |
| Grid cells | The custom iOS double-tap did not stop zoom | It cancelled a synthetic event, not the real touch | Removed it; current iOS fires dblclick natively |
| Server-side rendering | Risk of attaching listeners where there is no DOM | Hammer’s manager was a no-op on the server; the first native version was not | IgxTouchManager does nothing outside a browser |
| Changelog | Release notes for the already-shipped 22.0.0 were rewritten | The agent filed the change under the old version | Moved it to a new 22.1.0 section and restored the 22.0.0 entry |
| Agent Skills | Our AI skill files still told assistants to install HammerJS | Docs for AI tools were outside the original scope | Trimmed the stale instructions |
One regression slipped past all of us, me included. After the merge, dragging across a virtualized list of 100,000 items stuttered. My “no NgZone” instruction had a blind spot: in apps still using Zone.js, every pointermove now triggered a full change-detection pass. Idle list items were also capturing the pointer and fighting the list’s own scrolling.
The follow-up, #17471, lets the list run its high-frequency panMove outside the zone. It also skips gesture tracking entirely when an item cannot be panned.
The pattern is clear in hindsight. The AI handled everything a codebase can tell you: references, types, configs, tests. What it missed lived in browser behavior, device quirks and release history, which you only learn by holding the phone.
What you get from the change
If you build with Ignite UI for Angular 22.1 or later, here is what changes for you.
- One less dependency.
hammerjsand@types/hammerjsare no longer peer dependencies, andng addno longer asks about them. Delete them frompackage.json,angular.jsonand anyimport 'hammerjs'lines. - Touch works on Angular 22 out of the box. No more manual script wiring to get carousel swipes or drawer gestures.
- Zoneless-ready gestures. The gesture layer needs no
NgZone, in line with 22.1’s full zoneless support, while Zone.js apps keep working. - One gesture engine instead of four.
IgxTouchManagerreplaces copy-pasted logic, tracks a single pointer so a second finger cannot hijack a gesture, and does nothing during server-side rendering. - Better-behaved touch. Page scrolling is blocked only while a gesture is actually in progress, and idle list items no longer fight the list’s scrolling.
- A cleaner audit. One unmaintained package leaves every customer’s dependency review, and the library shed 135 lines net.
One caveat: if your own code uses Hammer gestures in templates, keep hammerjs and wire it up yourself, because Angular no longer does.
As for working with AI: Claude Opus 4.8 turned the mechanical refactoring into an hour’s work. The month after it is the part I would plan for again, with a device in hand.


