Frontend Master

JavaScript Curriculum

Event Handling
+50 XP

Event Handling

easy
~25 min·50 XP

The coffee shop menu needs clickable Order buttons, a search input that filters live, and a contact form that validates before submitting. Every interaction is driven by event handlers wired to state.

Event Handling

React uses synthetic events — cross-browser wrappers around native DOM events. You attach handlers as JSX props (onClick, onChange, onSubmit) and receive a SyntheticEvent object with the same API as native events.

Event Handler Patterns

Four ways to write event handlers — each with the right use case:

event-handlers.jsx

Handler defined before the return. Keeps JSX clean and makes the handler reusable, testable, and debuggable.

function OrderButton({ item, onOrder }) {
  const handleClick = () => {
    console.log('Ordering:', item.name)
    onOrder(item)
  }

  return (
    <button onClick={handleClick}>
      Order {item.name}
    </button>
  )
}
💡 Preferred for handlers with logic. Name it handle + Event or handle + Action: handleClick, handleSubmit, handleChange.
Live demo
// Click a button to see events
⚠️Never call the handler — pass it
`onClick={handleClick}` is correct — passes the function. `onClick={handleClick()}` is wrong — calls it immediately on render and passes the return value. The same applies to inline arrows: `onClick={() => handler(args)}` not `onClick={handler(args)}`.

SyntheticEvent — What You Get

Every event handler receives a SyntheticEvent. Explore what each event type gives you:

synthetic-events.jsx
onClicktriggers on: Mouse click
e.type"click"
Event name
e.target<button>
Element clicked
e.currentTarget<div>
Element with listener
e.clientX/Y{ x: 340, y: 210 }
Mouse position
e.button0
0=left, 1=mid, 2=right
Try it
ℹ️e.target vs e.currentTarget
`e.target` is the element the user actually interacted with. `e.currentTarget` is the element the handler is attached to. They differ when events bubble — useful for delegation patterns.

Controlled Form with Live State

A fully controlled form — every field wired to state, one handler for all inputs:

form-state.jsx
Live state
{
  "name": "",
  "email": "",
  "category": "coffee",
  "newsletter": false,
  "message": ""
}
One handleChange handles all inputs — reads name attr to know which field to update.
💡One handler for all fields
The pattern `onChange={handleChange}` with `name` attributes on every input lets one function handle all fields: `const handleChange = (e) => setForm(prev => ({ ...prev, [e.target.name]: e.target.value }))`. The `name` attribute becomes the state key.

Your Challenge

Build a live search: const [search, setSearch] = useState(''). Wire onChange to update it. Derive filtered = items.filter(i => i.name.toLowerCase().includes(search.toLowerCase())). Add onKeyDown: if e.key === 'Escape' clear the search. Show the count of visible items.

Challenge

Build a controlled search input that filters a list of menu items as you type. Wire onChange to update a searchTerm state. Derive filteredItems from the state. Add a keyboard handler that clears the input on Escape.

onClickonChangeonSubmitonKeyDownSyntheticEventpreventDefaultcontrolled-inputevent.target.valuehandler-patternsform-state
Event Handling | Nexus Learn