You've learned about components, props, and state. Now it's time to make your applications truly interactive! Events are how users interact with your app - clicking buttons, typing in inputs, submitting forms, and more. In this lesson, you'll learn how to handle events in React, the differences from HTML events, and the most common event types you'll use every day.
React Events vs HTML Events
React events look similar to HTML events, but with some important differences:
// HTML - lowercase, string
<button onclick="handleClick()">Click Me</button>
// React - camelCase, function reference
<button onClick={handleClick}>Click Me</button>
// Key differences:
// 1. React uses camelCase (onClick, not onclick)
// 2. React passes function reference (onClick={handleClick}, not "handleClick()")
// 3. React events are synthetic (cross-browser compatible)
// 4. You can't return false to prevent default (must use preventDefault)React Event Naming:
- Always camelCase:
onClick,onChange,onSubmit - Not lowercase like HTML: ❌
onclick, ❌onchange - Pass function reference:
onClick={handleClick} - Not a string: ❌
onClick="handleClick()"
onClick - Button Clicks
The most common event you'll use is onClick for handling button clicks:
Basic onClick Handler
function Button() {
// Define handler function
const handleClick = () => {
alert('Button clicked!')
}
return (
<button onClick={handleClick}>
Click Me
</button>
)
}
// When user clicks the button, handleClick runsInline Handler
function Button() {
return (
<button onClick={() => alert('Clicked!')}>
Click Me
</button>
)
}
// Inline arrow function - useful for simple actions
// But prefer separate functions for complex logicHandler with State
function Counter() {
const [count, setCount] = React.useState(0)
const handleIncrement = () => {
setCount(count + 1)
}
const handleDecrement = () => {
setCount(count - 1)
}
const handleReset = () => {
setCount(0)
}
return (
<div>
<p>Count: {count}</p>
<button onClick={handleIncrement}>+</button>
<button onClick={handleDecrement}>-</button>
<button onClick={handleReset}>Reset</button>
</div>
)
}⚠️ Common onClick Mistake
❌ Wrong: onClick={handleClick()}
This calls the function immediately during render!
✅ Correct: onClick={handleClick}
This passes the function to be called on click
✅ Also correct: onClick={() => handleClick()}
Wrap in arrow function if you need to pass arguments
onChange - Input Changes
Use onChange to respond to input field changes:
Text Input
function NameInput() {
const [name, setName] = React.useState('')
const handleChange = (event) => {
setName(event.target.value) // Get the input value
}
return (
<div>
<input
type="text"
value={name}
onChange={handleChange}
placeholder="Enter your name"
/>
<p>Hello, {name || 'stranger'}!</p>
</div>
)
}
// event.target.value contains the current input valueInline onChange
function SearchBox() {
const [query, setQuery] = React.useState('')
return (
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search..."
/>
)
}
// Inline is fine for simple value updates
// 'e' is short for 'event' - commonly usedCheckbox
function ToggleSwitch() {
const [isChecked, setIsChecked] = React.useState(false)
const handleChange = (event) => {
setIsChecked(event.target.checked) // Use .checked, not .value!
}
return (
<label>
<input
type="checkbox"
checked={isChecked}
onChange={handleChange}
/>
{isChecked ? 'Enabled' : 'Disabled'}
</label>
)
}Select Dropdown
function ColorPicker() {
const [color, setColor] = React.useState('red')
return (
<div>
<select value={color} onChange={(e) => setColor(e.target.value)}>
<option value="red">Red</option>
<option value="blue">Blue</option>
<option value="green">Green</option>
</select>
<p>Selected color: {color}</p>
</div>
)
}Textarea
function MessageBox() {
const [message, setMessage] = React.useState('')
return (
<div>
<textarea
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="Enter your message..."
rows={4}
/>
<p>Character count: {message.length}</p>
</div>
)
}onSubmit - Form Submission
Handle form submissions with onSubmit:
function LoginForm() {
const [email, setEmail] = React.useState('')
const [password, setPassword] = React.useState('')
const handleSubmit = (event) => {
event.preventDefault() // Prevent page reload!
console.log('Submitted:', { email, password })
// Here you would send data to server
}
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
/>
<button type="submit">Login</button>
</form>
)
}
// IMPORTANT: Always use event.preventDefault() in onSubmit
// to prevent the default form submission behavior (page reload)Form Submission - Don't Forget preventDefault!
Without event.preventDefault(), the form will submit traditionally (page will reload). This is almost never what you want in a React app. Always call event.preventDefault() at the start of your onSubmit handler.
Other Common Events
Mouse Events
function MouseEvents() {
const [status, setStatus] = React.useState('Idle')
return (
<div>
<button
onClick={() => setStatus('Clicked')}
onDoubleClick={() => setStatus('Double-clicked')}
onMouseEnter={() => setStatus('Mouse entered')}
onMouseLeave={() => setStatus('Mouse left')}
onMouseDown={() => setStatus('Mouse down')}
onMouseUp={() => setStatus('Mouse up')}
>
Hover or click me
</button>
<p>Status: {status}</p>
</div>
)
}
// Common mouse events:
// onClick - single click
// onDoubleClick - double click
// onMouseEnter - mouse enters element
// onMouseLeave - mouse leaves element
// onMouseDown - mouse button pressed
// onMouseUp - mouse button released
// onMouseMove - mouse moves over elementKeyboard Events
function KeyboardEvents() {
const [key, setKey] = React.useState('')
const handleKeyDown = (event) => {
setKey(`Key pressed: ${event.key}`)
}
const handleKeyPress = (event) => {
if (event.key === 'Enter') {
alert('Enter pressed!')
}
}
return (
<div>
<input
type="text"
onKeyDown={handleKeyDown}
onKeyPress={handleKeyPress}
placeholder="Type something..."
/>
<p>{key}</p>
</div>
)
}
// Common keyboard events:
// onKeyDown - key is pressed down
// onKeyUp - key is released
// onKeyPress - key press (deprecated, use onKeyDown)Focus Events
function FocusEvents() {
const [focused, setFocused] = React.useState(false)
return (
<div>
<input
type="text"
onFocus={() => setFocused(true)}
onBlur={() => setFocused(false)}
placeholder="Click to focus"
/>
<p>{focused ? 'Input is focused' : 'Input is not focused'}</p>
</div>
)
}
// Common focus events:
// onFocus - element gains focus
// onBlur - element loses focusScroll Events
function ScrollTracker() {
const [scrollTop, setScrollTop] = React.useState(0)
const handleScroll = (event) => {
setScrollTop(event.target.scrollTop)
}
return (
<div
onScroll={handleScroll}
style={{ height: '200px', overflow: 'auto' }}
>
<div style={{ height: '1000px' }}>
<p>Scroll position: {scrollTop}px</p>
<p>Scroll down to see the value change...</p>
</div>
</div>
)
}Passing Arguments to Handlers
Using Arrow Functions
function ButtonList() {
const handleClick = (id) => {
alert(`Button ${id} clicked`)
}
return (
<div>
<button onClick={() => handleClick(1)}>Button 1</button>
<button onClick={() => handleClick(2)}>Button 2</button>
<button onClick={() => handleClick(3)}>Button 3</button>
</div>
)
}
// Wrap in arrow function to pass argumentsUsing bind (Alternative)
function ButtonList() {
const handleClick = (id, event) => {
alert(`Button ${id} clicked`)
}
return (
<div>
<button onClick={handleClick.bind(null, 1)}>Button 1</button>
<button onClick={handleClick.bind(null, 2)}>Button 2</button>
<button onClick={handleClick.bind(null, 3)}>Button 3</button>
</div>
)
}
// bind creates a new function with preset arguments
// Less common than arrow functionsPassing Data Attributes
function ProductList() {
const products = [
{ id: 1, name: 'Laptop' },
{ id: 2, name: 'Mouse' },
{ id: 3, name: 'Keyboard' }
]
const handleClick = (event) => {
const id = event.target.dataset.id
const name = event.target.dataset.name
alert(`Clicked: ${name} (ID: ${id})`)
}
return (
<div>
{products.map(product => (
<button
key={product.id}
data-id={product.id}
data-name={product.name}
onClick={handleClick}
>
{product.name}
</button>
))}
</div>
)
}
// Use data-* attributes to store info on elements
// Access via event.target.datasetInteractive Demo
💡 Tip: Edit the code above and click "Run" to see your changes
Event Handler Patterns
Pattern 1: Named Handler Functions
// ✅ Good for complex logic
function Form() {
const [data, setData] = React.useState({ name: '', email: '' })
const handleNameChange = (event) => {
setData({ ...data, name: event.target.value })
}
const handleEmailChange = (event) => {
setData({ ...data, email: event.target.value })
}
const handleSubmit = (event) => {
event.preventDefault()
console.log('Submitting:', data)
}
return (
<form onSubmit={handleSubmit}>
<input value={data.name} onChange={handleNameChange} />
<input value={data.email} onChange={handleEmailChange} />
<button type="submit">Submit</button>
</form>
)
}Pattern 2: Generic Handler
// ✅ Good for forms with many fields
function Form() {
const [data, setData] = React.useState({ name: '', email: '', phone: '' })
const handleChange = (event) => {
const { name, value } = event.target
setData({ ...data, [name]: value })
}
return (
<form>
<input name="name" value={data.name} onChange={handleChange} />
<input name="email" value={data.email} onChange={handleChange} />
<input name="phone" value={data.phone} onChange={handleChange} />
</form>
)
}
// Single handler for all inputs - uses the 'name' attributePattern 3: Inline for Simple Actions
// ✅ Good for simple, one-line actions
function Counter() {
const [count, setCount] = React.useState(0)
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>+</button>
<button onClick={() => setCount(count - 1)}>-</button>
<button onClick={() => setCount(0)}>Reset</button>
</div>
)
}Common Event Handling Mistakes
1. Calling Function Immediately
// ❌ Wrong - calls function during render
<button onClick={handleClick()}>Click</button>
// ✅ Correct - passes function reference
<button onClick={handleClick}>Click</button>
// ✅ Also correct - arrow function
<button onClick={() => handleClick()}>Click</button>2. Forgetting preventDefault
// ❌ Wrong - form will reload page
const handleSubmit = (event) => {
console.log('Submitting...')
// Page reloads here!
}
// ✅ Correct - prevent default behavior
const handleSubmit = (event) => {
event.preventDefault()
console.log('Submitting...')
}3. Wrong Event Property for Checkboxes
// ❌ Wrong - checkboxes use .checked, not .value
const handleChange = (event) => {
setIsChecked(event.target.value) // This won't work!
}
// ✅ Correct - use .checked for checkboxes
const handleChange = (event) => {
setIsChecked(event.target.checked)
}4. Not Using Controlled Components
// ❌ Bad - uncontrolled (input value not in state)
function Form() {
const handleChange = (event) => {
console.log(event.target.value)
}
return <input onChange={handleChange} />
}
// ✅ Good - controlled (value in state)
function Form() {
const [value, setValue] = React.useState('')
return (
<input
value={value}
onChange={(e) => setValue(e.target.value)}
/>
)
}Key Takeaways
- React events use camelCase:
onClick,onChange,onSubmit - Pass function reference, not call:
onClick={fn}, notonClick={fn()} - Use
event.target.valuefor input values - Use
event.target.checkedfor checkbox values - Always use
event.preventDefault()in onSubmit - Use inline arrow functions to pass arguments
- Common events: onClick, onChange, onSubmit, onKeyDown, onFocus, onBlur
- Event handlers receive the event object as first argument
- Prefer named functions for complex logic
- Use inline functions for simple, one-line actions
- Use generic handlers for forms with many fields
- Always use controlled components for form inputs
What's Next?
You now know how to handle user interactions in React! You can respond to clicks, input changes, form submissions, and more.
But there's more to learn about events. In the next lesson, you'll dive deeper into event objects:
- What information is in the event object
- How to access event properties
- Using preventDefault and stopPropagation
- Understanding synthetic events
- Advanced event handling patterns
Get ready to become an event handling expert! 🎯