01 — Purpose

Justify the script first

The best JavaScript in a pull request is often the JavaScript you delete.

Use this checklist on JavaScript and TypeScript changes — modules, event handlers, and client enhancements. See JavaScript standards for principles. Pair with HTML and CSS review when custom controls or layout behaviour change.

02 — Necessity

Is JavaScript necessary?

Ask whether the platform already solves it — not whether you can solve it with a library.

  • the feature still works without this script — progressive enhancement, not replacement
  • native behaviour considered — forms, details, dialog, validation, navigation
  • new dependency justified — not added because it is popular
  • inline onclick and globals avoided — behaviour lives in modules
  • script load strategy appropriate — defer, async, or dynamic import; not blocking the critical path without reason

03 — Clarity

Readability and structure

Production code is read far more than it is written.

  • readable on first pass — names and steps explain intent
  • smallest sensible solution — not the cleverest one-liner
  • modules scoped to a feature — not another 1,200-line shared file
  • shared utilities earn their place — no mystery abstractions
  • comments explain trade-offs and constraints — not obvious lines
  • TypeScript types or JSDoc where contracts help reviewers

04 — Events

Events and the DOM

Event code is where focus bugs and memory leaks hide.

  • addEventListener in modules — listeners removed or scoped when components tear down
  • delegation used where many similar targets share one handler
  • DOM queries guarded when templates differ — optional elements do not throw
  • DOM updates batched where possible — no thrashing layout in loops
  • user input validated on the client for UX — server still authoritative
  • async flows handle errors and loading — not only the happy path

05 — Performance

Performance and dependencies

Every kilobyte is a future maintenance cost.

  • bundle impact understood — new imports and tree-shaking considered
  • non-critical code lazy-loaded where it helps
  • third-party scripts challenged — analytics, widgets, tags
  • duplicate listeners and polling avoided
  • performance review checklist flagged for heavy or hot-path changes

06 — Accessibility

Accessibility in JavaScript

Custom behaviour must restore what native controls gave you for free.

  • keyboard access for custom controls — not mouse-only interactions
  • focus managed deliberately in modals, drawers, and menus — traps escape with Escape
  • expanded, selected, and disabled states synced with attributes
  • dynamic updates announced when they matter — live regions used sparingly
  • loading and error states perceivable — not silent failures
  • accessibility QA checklist flagged when interaction patterns change

07 — Sign-off

Before you approve

Is JavaScript the best solution here — not merely a possible one?

  • tests cover logic that would hurt users if it broke — not theatre coverage
  • no secrets, tokens, or private keys in client bundles
  • console logging and debug code removed
  • another developer could change this safely without a archaeology expedition