Ccodemod

codemod/javascript-use-add-remove-event-listener

Codemod for JavaScript (browser DOM code) that rewrites direct `on*` handler property usage (e.g., `elem.onclick = fn`, `window.onresize = fn`) to explicit `addEventListener`/`removeEventListener` patterns, improving consistency, composability, and lint compliance (`unicorn/prefer-add-event-listener`).

javascripttypescriptdomeventslint
Public
0 executions

Run locally

npx codemod @codemod/javascript-use-add-remove-event-listener

@codemod/javascript-use-add-remove-event-listener

Codemod for JavaScript (browser DOM code) that rewrites direct on* handler property usage (e.g., elem.onclick = fn, window.onresize = fn) to explicit addEventListener/removeEventListener patterns, improving consistency, composability, and lint compliance (unicorn/prefer-add-event-listener).

Installation

bash

Usage

This codemod targets browser-oriented *.js, *.jsx, *.mjs, *.cjs, *.ts, and *.tsx files and rewrites safe on* property assignments on likely DOM EventTarget receivers.

Rewritten patterns:

  • el.onclick = onClick -> el.addEventListener('click', onClick)
  • window.onresize = handleResize -> window.addEventListener('resize', handleResize)
  • doc.body.onkeydown = (event) => key(event) -> doc.body.addEventListener('keydown', (event) => key(event))
  • el.onclick = handler; ... el.onclick = null -> el.addEventListener('click', handler); ... el.removeEventListener('click', handler)
  • Inline function teardown pairs are hoisted to a stable local listener variable before converting to addEventListener/removeEventListener

Receiver inference is intentionally conservative. The codemod rewrites globals like window and document, variables typed as DOM event targets, values derived from common DOM APIs such as document.getElementById() and document.querySelector(), document aliases like doc: Document, and typed this.<field> DOM wrappers inside classes.

Preserved as-is by default:

  • Computed properties such as obj['onclick'] = fn or el['on' + evt] = fn
  • Camel-case custom properties such as obj.onClick = fn
  • Non-DOM or unknown receivers such as customStore.onchange = fn
  • Read-only access such as if (el.onclick)
  • Invalid assignments such as el.onclick = 42
  • Reassignment chains such as el.onclick = first; el.onclick = second;
  • Unmatched clears such as el.onclick = null

Pairing is intentionally conservative. The codemod only rewrites add/remove pairs when the setup and clear are compatible within the same lexical scope and the handler reference is valid at the clear site. Unmatched clears and ambiguous overwrite patterns are left unchanged.

Development

bash

License

MIT

Before

This is one example from the codemod's test cases. The codemod may handle many more cases.

Ready to contribute?

Build your own codemod and share it with the community.