Learning Objectives
- Bind a handler three ways: inline attribute, element property, and
addEventListener - Explain why inline handlers mix content with behavior, and why that costs you
- Stack multiple listeners on one element and predict their firing order
- Use listener options:
once, and removing a handler you added
Three ways to say “call me”
Event binding has accumulated in layers, and each layer is still supported. Oldest first:
1. The inline attribute
JavaScript inside your markup. It works, and it is how everyone did it in 1997 — but it puts behavior in the content layer, binds you to global function names, and gives you exactly one handler per attribute. The same reasoning that moved styling out of <font> tags and into CSS moves behavior out of onclick attributes and into script.
2. The element property
Behavior is in the script layer now, which is real progress. But a property holds one value: assign a second handler and the first is silently gone. Two pieces of code that both want to hear about clicks on the same element cannot share a property.
3. addEventListener
Many listeners per element, per event type, firing in the order added. Options like once for self-removing handlers, and clean removal — provided you kept a reference to the function, which is why named functions beat anonymous ones for any handler you might need to detach.
addEventListener('click', doSomething()) — with parentheses. That calls the function now and binds its return value (usually undefined). You are handing the browser a function to call later, not calling it yourself.Live demo
The demo below is a survey of the whole model. Sections 1 and 2 are this step: compare property binding against addEventListener, watch a once handler expire, and stack three handlers on one button. Sections 3–6 — the event object, propagation, delegation, passive listeners — are previews of the steps ahead; press things now, and come back when each topic gets its own step.
Notice the pattern every demo in this series uses: no inline handlers anywhere, one small $() helper for selection, and results written into an <output> element with aria-live so the result is announced, not just painted.
Why this is the fault line
The three bindings are not three equal styles; they mark the boundary between page-as-document and page-as-program. Inline handlers scatter program logic through the markup where it cannot be tested, reused, or removed. addEventListener keeps the contract in one place and makes the page's behavior something you can reason about — and, in step 4, something you can centralize down to a single listener for an entire list. Every demo from here forward assumes it.
onClick={...} in JSX) deliberately echo the inline style — but that is syntax the framework compiles into addEventListener calls. Recognizing the raw forms tells you what the abstraction is actually doing.Next Steps
In Step 2: The event object, we look at what your handler is actually handed when the call comes:
- Read
type,target, coordinates, keys, and modifiers - Cancel default behavior with
preventDefault() - Build an event watcher you can point at any element