---
title: "`wheel` / `touchstart` / `touchmove` listener without `{ passive: true }` (lint/scroll-listener-nonpassive)"
description: "lint/scroll-listener-nonpassive: Non-passive wheel/touch listeners force the browser to wait for JavaScript before scrolling, which causes visible scroll…"
canonical: https://void-design.vercel.app/rules/lint/scroll-listener-nonpassive
lastModified: 2026-09-16
---

# `wheel` / `touchstart` / `touchmove` listener without `{ passive: true }`

`lint/scroll-listener-nonpassive` · severity **warn** · category Lint · detected by `void lint` and `void audit`

## Why it matters

Non-passive wheel/touch listeners force the browser to wait for JavaScript before scrolling, which causes visible scroll jank on mobile.

## How to fix it

Pass `{ passive: true }`. If you truly need `preventDefault()`, pass `{ passive: false }` explicitly and scope the listener to the smallest element. For scroll-linked effects prefer IntersectionObserver or CSS scroll-driven animations.

## Example

```ts
el.addEventListener('touchmove', onMove, { passive: true })
```

## References

- https://web.dev/articles/uses-passive-event-listeners

## More lint rules

`void lint` reports 67 rules in this category. Static source checks with no browser: Tailwind v4 silent failures, Next.js 16 API traps, React render-body bugs, accessibility markup, SEO files and motion hygiene.

- `motionvalue-subscribe-in-render` MotionValue `.on("change")` subscription in a component body — [lint/motionvalue-subscribe-in-render](https://void-design.vercel.app/rules/lint/motionvalue-subscribe-in-render)
- `webgl-in-map` WebGL canvas rendered inside `.map()` — [lint/webgl-in-map](https://void-design.vercel.app/rules/lint/webgl-in-map)
- `raf-without-cancel` `requestAnimationFrame` loop in an effect without `cancelAnimationFrame` — [lint/raf-without-cancel](https://void-design.vercel.app/rules/lint/raf-without-cancel)
- `listener-without-cleanup` Event listener or interval added in an effect without cleanup — [lint/listener-without-cleanup](https://void-design.vercel.app/rules/lint/listener-without-cleanup)
- `unload-listener` `unload` event listener — [lint/unload-listener](https://void-design.vercel.app/rules/lint/unload-listener)
- `useeffect-fetch` Page fetches its data in `useEffect` — [lint/useeffect-fetch](https://void-design.vercel.app/rules/lint/useeffect-fetch)
- `div-button` Clickable `<div>`/`<span>` without button semantics — [lint/div-button](https://void-design.vercel.app/rules/lint/div-button)
- `dangerously-set-jsonld-unescaped` JSON-LD injected with `JSON.stringify` without escaping `<` — [lint/dangerously-set-jsonld-unescaped](https://void-design.vercel.app/rules/lint/dangerously-set-jsonld-unescaped)

Detected by `void lint` and `void audit`. Explain it in a terminal: `void rules lint/scroll-listener-nonpassive`
