React Events & Forms

onClick, onChange, controlled components, and building interactive forms

Events onClick onChange Controlled Forms

Table of Contents

1. Introduction: Events in React

In web development, events are actions that happen in the browser that your code can respond to. Examples include:

  • User clicks a button (onClick)
  • User types in an input field (onChange)
  • User submits a form (onSubmit)
  • User hovers over an element (onMouseEnter)

React handles events slightly differently than plain HTML/JavaScript, but the concepts are very similar.

Analogy: Events are like notifications. When a user clicks a button, React says "Hey! Someone just clicked that button!" and your code can decide what to do next.

2. React Events vs DOM Events: Key Differences

AspectRegular DOM / HTMLReact
NamingLowercase (onclick)CamelCase (onClick)
Handler ValueString of function nameActual JavaScript function reference
Default Behaviorreturn falsepreventDefault() explicitly
Event ObjectNative browser eventSyntheticEvent wrapper
Compare<!-- HTML --> <button onclick="handleClick()">Click</button> {/* React */} <button onClick={handleClick}>Click</button>

3. Handling Events in React

3.1 Basic Event Handling Syntax

JSXfunction App() { const handleClickInline = () => console.log("Button clicked!"); return ( <div> <button onClick={() => console.log("Clicked!")}>Click Me</button> <button onClick={handleClickInline}>Click Me Too</button> </div> ); }

3.2 Event Handler Functions

JSXfunction Counter() { const [count, setCount] = useState(0); const handleIncrement = () => setCount(count + 1); const handleDecrement = () => { if (count > 0) 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> ); }

3.3 Passing Arguments to Event Handlers

JSXfunction TodoList() { const deleteTodo = (id, title) => console.log(`Deleting ${title} (ID: ${id})`); return ( <button onClick={() => deleteTodo(1, "Learn React")}>Delete Todo 1</button> ); }

3.4 Accessing the Event Object

React passes a SyntheticEvent object to your handlers:

PropertyDescription
event.targetThe DOM element that triggered the event
event.currentTargetThe element the handler is attached to
event.typeEvent type (e.g., "click", "change")
event.preventDefault()Prevents default browser behavior
event.stopPropagation()Stops event bubbling
JSXconst handleInputChange = (event) => { console.log("Input value:", event.target.value); console.log("Input name:", event.target.name); };

4. onClick Event: Clicks and Interactions

The onClick event fires when an element is clicked. It works on any HTML element, not just buttons.

4.1 Basic onClick Usage

JSXfunction ClickExamples() { const [message, setMessage] = useState(""); return ( <div> <button onClick={() => setMessage("Button clicked!")}>Click Button</button> <div onClick={() => setMessage("Div clicked!")} style={{ cursor: "pointer" }}> Click this div </div> <p>{message}</p> </div> ); }

4.2 Passing Parameters to onClick

JSX{products.map(product => ( <button key={product} onClick={() => handleSelect(product)}> {product} </button> ))}

4.3 Toggle Example with onClick

JSXfunction ToggleButton() { const [isOn, setIsOn] = useState(false); return ( <button onClick={() => setIsOn(!isOn)}> {isOn ? "ON" : "OFF"} </button> ); }

4.4 Common onClick Patterns

  • Increment/Decrement: setCount(prev => prev + 1)
  • Add/Remove items: setItems([...items, newItem]) / slice(0, -1)
  • Show/Hide: setIsVisible(!isVisible) with conditional render

5. onChange Event: Capturing User Input

The onChange event fires whenever the value of an input element changes. For text inputs, this happens on every keystroke.

5.1 Basic onChange Usage

JSXfunction BasicOnChange() { const [text, setText] = useState(""); return ( <div> <input value={text} onChange={(e) => setText(e.target.value)} /> <p>You typed: {text}</p> <p>Character count: {text.length}</p> </div> ); }

5.2 Accessing Input Values

JSXconst handleChange = (event) => { const { name, value, type, checked } = event.target; setFormData(prev => ({ ...prev, [name]: value })); };

5.3 Different Input Types (text, checkbox, radio, select, textarea)

JSXconst handleChange = (event) => { const { name, value, type, checked } = event.target; setFormData(prev => ({ ...prev, [name]: type === "checkbox" ? checked : value })); }; // checkbox: checked={formData.checkbox} // radio: checked={formData.radio === "option1"} // select: value={formData.select} // textarea: value={formData.textarea}

5.4 Real-time Validation Example

JSXconst handleChange = (event) => { const newEmail = event.target.value; setEmail(newEmail); validateEmail(newEmail); // Validate on every keystroke };

6. Form Inputs in React

6.1 Types of Form Inputs

React supports all HTML input types: text, password, email, number, tel, url, search, color, date, time, file, and more.

6.2 Handling Multiple Inputs

JSXconst handleChange = (event) => { const { name, value, type, checked } = event.target; setFormData(prev => ({ ...prev, [name]: type === "checkbox" ? checked : value })); };

6.3 Form Submission

JSXconst handleSubmit = async (event) => { event.preventDefault(); // VERY IMPORTANT: Prevents page reload setLoading(true); try { await submitToApi(formData); setSubmitted(true); } finally { setLoading(false); } };

6.4 Preventing Default Behavior

JSXconst handleFormSubmit = (event) => { event.preventDefault(); // Stops page reload }; const handleLinkClick = (event) => { event.preventDefault(); // Stops navigation };

7. Controlled Components (The React Way)

7.1 What are Controlled Components?

A controlled component is an input whose value is controlled by React state.

JSX// CONTROLLED function ControlledInput() { const [value, setValue] = useState(""); return <input value={value} onChange={(e) => setValue(e.target.value)} />; } // UNCONTROLLED — DOM manages value function UncontrolledInput() { return <input />; }

7.2 Controlled vs Uncontrolled Components

AspectControlledUncontrolled
Value sourceReact stateDOM itself
Access valueFrom stateUsing ref
ValidationReal-time, easyMore difficult
React recommended✅ Yes⚠️ Only when necessary

7.3 Implementing Controlled Components

Bind value/checked from state and update via onChange for text, checkbox, radio, select, and textarea inputs.

7.4 Complete Controlled Form Example

JSXfunction ControlledForm() { const [formData, setFormData] = useState({ fullName: "", email: "", password: "", confirmPassword: "", age: "", gender: "", interests: [], country: "", terms: false }); const [errors, setErrors] = useState({}); const [touched, setTouched] = useState({}); const handleChange = (event) => { const { name, value, type, checked } = event.target; setFormData(prev => ({ ...prev, [name]: type === "checkbox" ? (name === "interests" ? (checked ? [...prev.interests, value] : prev.interests.filter(i => i !== value)) : checked) : value })); if (errors[name]) setErrors(prev => ({ ...prev, [name]: "" })); }; const handleBlur = (event) => { setTouched(prev => ({ ...prev, [event.target.name]: true })); validateField(event.target.name); }; const validateField = (fieldName) => { /* validation logic */ }; const handleSubmit = (event) => { event.preventDefault(); if (validateForm()) { console.log("Form submitted:", formData); } }; return ( <form onSubmit={handleSubmit}> <input name="fullName" value={formData.fullName} onChange={handleChange} onBlur={handleBlur} /> <input name="email" type="email" value={formData.email} onChange={handleChange} onBlur={handleBlur} /> <input name="password" type="password" value={formData.password} onChange={handleChange} /> <input name="terms" type="checkbox" checked={formData.terms} onChange={handleChange} /> <button type="submit">Register</button> </form> ); }

7.5 Two-Way Data Binding

JSXfunction TwoWayBinding() { const [name, setName] = useState(""); return ( <div> <input value={name} onChange={(e) => setName(e.target.value)} /> <p>You typed: {name}</p> <button onClick={() => setName("")}>Clear</button> <button onClick={() => setName("Hello World")}>Set Text</button> </div> ); }

8. Other Useful Events

8.1 onFocus and onBlur

Use onFocus when a field gains focus and onBlur to validate when the user leaves a field.

8.2 onSubmit

JSX<form onSubmit={handleSubmit}> <input value={search} onChange={(e) => setSearch(e.target.value)} /> <button type="submit">Search</button> </form>

8.3 onKeyDown, onKeyUp, onKeyPress

JSXconst handleKeyDown = (event) => { if (event.key === "Enter") { event.preventDefault(); submitForm(); } if (event.key === "Escape") setInputValue(""); };

8.4 onMouseEnter and onMouseLeave

JSX<div onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} onMouseMove={(e) => setMousePosition({ x: e.clientX, y: e.clientY })} > {isHovered ? "Mouse is inside!" : "Hover over me"} </div>

9. Complete Working Examples

9.1 Example 1: Login Form (Controlled Components)

JSXfunction LoginForm() { const [credentials, setCredentials] = useState({ email: "", password: "" }); const [errors, setErrors] = useState({}); const [loading, setLoading] = useState(false); const [showPassword, setShowPassword] = useState(false); const handleChange = (event) => { const { name, value } = event.target; setCredentials(prev => ({ ...prev, [name]: value })); if (errors[name]) setErrors(prev => ({ ...prev, [name]: "" })); }; const handleSubmit = async (event) => { event.preventDefault(); if (!validateForm()) return; setLoading(true); try { await loginApi(credentials); } finally { setLoading(false); } }; return ( <form onSubmit={handleSubmit}> <input name="email" type="email" value={credentials.email} onChange={handleChange} /> <input name="password" type={showPassword ? "text" : "password"} value={credentials.password} onChange={handleChange} /> <button type="button" onClick={() => setShowPassword(!showPassword)}>{showPassword ? "Hide" : "Show"}</button> <button type="submit" disabled={loading}>{loading ? "Logging in..." : "Login"}</button> </form> ); }

9.2 Example 2: Todo App with Form Inputs

Features: add todo form, priority select, filter buttons, inline edit, toggle complete, delete, stats.

JSXfunction TodoApp() { const [todos, setTodos] = useState([]); const [newTodo, setNewTodo] = useState(""); const [priority, setPriority] = useState("medium"); const [filter, setFilter] = useState("all"); const addTodo = (event) => { event.preventDefault(); if (newTodo.trim()) { setTodos([...todos, { id: Date.now(), text: newTodo, completed: false, priority }]); setNewTodo(""); } }; return ( <div> <form onSubmit={addTodo}> <input value={newTodo} onChange={(e) => setNewTodo(e.target.value)} /> <select value={priority} onChange={(e) => setPriority(e.target.value)}> <option value="low">Low</option> <option value="medium">Medium</option> <option value="high">High</option> </select> <button type="submit">Add Todo</button> </form> {/* filtered list with toggle, edit, delete */} </div> ); }

9.3 Example 3: Multi-Step Form

JSXfunction MultiStepForm() { const [step, setStep] = useState(1); const [formData, setFormData] = useState({ fullName: "", email: "", phone: "", address: "", city: "", zipCode: "", interests: [], newsletter: false }); const nextStep = () => { if (step === 1 && validateStep1()) setStep(2); if (step === 2 && validateStep2()) setStep(3); }; const handleSubmit = (event) => { event.preventDefault(); console.log("Form submitted:", formData); }; return ( <form onSubmit={handleSubmit}> {step === 1 && <PersonalInfoFields />} {step === 2 && <AddressFields />} {step === 3 && <PreferencesFields />} {step > 1 && <button type="button" onClick={() => setStep(step - 1)}>Previous</button>} {step < 3 && <button type="button" onClick={nextStep}>Next</button>} {step === 3 && <button type="submit">Submit</button>} </form> ); }

10. Common Mistakes and Best Practices

MistakeWhy It's WrongCorrect Way
Forgetting preventDefault()Page reloads, state resetsAlways call in form onSubmit
value without onChangeInput becomes read-onlyAlways provide onChange
No loading statesMultiple submissionsDisable button during async
Validate password on every keystrokePremature errorsValidate on blur or submit
JSX// GOOD: descriptive names, loading state, proper types const handleEmailChange = (event) => { ... }; const [isSubmitting, setIsSubmitting] = useState(false); <input type="email" /> // BAD: inline 20-line onClick, no error handling <button onClick={() => { /* complex logic */ }}>

11. Summary Cheat Sheet

JSX// EVENT BASICS <button onClick={handler}>Click</button> <button onClick={() => handler(arg)}>Click</button> // COMMON EVENTS onClick | onChange | onSubmit | onFocus | onBlur | onKeyDown | onMouseEnter // CONTROLLED COMPONENT const [value, setValue] = useState(""); <input value={value} onChange={(e) => setValue(e.target.value)} /> // CHECKBOX / RADIO / SELECT checked={isChecked} onChange={(e) => setIsChecked(e.target.checked)} checked={selected === "a"} onChange={(e) => setSelected(e.target.value)} <select value={selected} onChange={(e) => setSelected(e.target.value)}> // FORM SUBMISSION const handleSubmit = async (event) => { event.preventDefault(); if (!validate()) return; setLoading(true); try { await submitData(); } finally { setLoading(false); } }; // MULTIPLE INPUTS const handleChange = (e) => { const { name, value, type, checked } = e.target; setForm(prev => ({ ...prev, [name]: type === "checkbox" ? checked : value })); };

Next Steps

  • useEffect Hook – Side effects, API calls, data fetching
  • Conditional Rendering – Showing/hiding elements based on state
  • Lists and Keys – Rendering dynamic lists
  • Form Validation Libraries – Formik, React Hook Form
  • Custom Hooks – Reusing logic across components

React Events & Forms MCQ Practice

10 Basic MCQs 10 Advanced MCQs

10 Basic React Events & Forms MCQs

1

React events use camelCase such as:

AonClick
Bonclick
CONCLICK
Dclick-handler
Explanation: DOM uses lowercase; React uses onClick.
2

To prevent default form submit you call:

Ae.preventDefault() in handler
Breturn false only in HTML
CstopPropagation only
Dalert()
Explanation: Handle submit and call preventDefault.
3

Passing arguments to handlers often uses:

AArrow function wrapper () => handle(id)
Bhandle(id) directly in onClick attribute
Cglobal variables only
DinnerHTML
Explanation: onClick={() => handle(id)} avoids immediate invocation.
4

A controlled input has:

Avalue bound to state and onChange updater
BNo onChange
Cref only always
DdefaultValue only in production
Explanation: React state is single source of truth.
5

onChange on text input receives:

ASynthetic event with target.value
BOnly mouse coordinates
CPromise
DCSS class
Explanation: e.target.value reads input text.
6

Synthetic events in React:

AWrap native events for cross-browser consistency
BDisable all events
CAre slower than native always
DReplace state
Explanation: React normalizes event behavior.
7

Checkbox controlled pattern uses:

Achecked + onChange
Bvalue only
Ctype=text
Ddisabled always
Explanation: Boolean checked state for checkboxes.
8

Select dropdown controlled value comes from:

Astate via value prop on select
Bdocument.cookie
Cprops only immutable
DCSS
Explanation: <select value={city} onChange={...}>.
9

Form submit handler is attached with:

AonSubmit on form element
BonClick on body only
ConLoad
DonResize
Explanation: Use onSubmit not button click for forms.
10

e.stopPropagation() prevents:

AEvent bubbling to parent elements
BDefault browser action always
CState updates
DRe-renders
Explanation: preventDefault vs stopPropagation serve different purposes.

10 Advanced React Events & Forms MCQs

1

Uncontrolled inputs use:

Aref to read DOM value
Bvalue + onChange only
CContext only
DRedux only
Explanation: useRef + ref on input for uncontrolled pattern.
2

Multiple inputs one handler pattern:

Aname attribute + setState from e.target.name
BSeparate component per key always
CNo state
DOnly uncontrolled
Explanation: Dynamic key: [e.target.name]: e.target.value.
3

React 17+ attaches events to:

ARoot container (delegation)
BEvery DOM node individually
Cwindow only in IE
DShadow DOM only
Explanation: Delegation changed from document in React 17.
4

Passing e.persist() was needed when:

AUsing async code with pooled SyntheticEvent (legacy)
BUsing hooks
CUsing Vite
DUsing TypeScript
Explanation: React 17+ removed event pooling.
5

File input is often uncontrolled because:

AFile path cannot be set via value for security
BFiles use text value prop
CReact forbids files
DonChange not supported
Explanation: Read files from ref or event target.files.
6

Debouncing search input typically uses:

AsetTimeout/clearTimeout or custom hook
BpreventDefault only
CdangerouslySetInnerHTML
DStrict Mode off
Explanation: Debounce limits API calls while typing.
7

Form libraries like React Hook Form optimize by:

AReducing re-renders via uncontrolled refs
BRemoving JSX
CDisabling validation
DUsing jQuery
Explanation: Less state churn on every keystroke.
8

Keyboard Enter in textarea vs form:

AEnter may newline in textarea; form may submit on Enter
BAlways submits
CNever fires events
DBlocked by React
Explanation: Handle onKeyDown if custom behavior needed.
9

Accessibility: label htmlFor connects to:

Ainput id for screen readers
BCSS class only
Crouter path
Dnpm script
Explanation: Associate labels with inputs via id.
10

Controlled component pitfall with rapid typing:

ALag if parent re-render is expensive—optimize or local state
BAlways faster than native
CCannot use state
DBreaks JSX
Explanation: Profile and defer heavy parent updates.

15 React Events & Forms Interview Questions & Answers

Easy Medium Hard
1How do you handle clicks in React?easy
Answer: Attach onClick={handler} to JSX elements with camelCase event names.
2What is a controlled component?easy
Answer: Form element whose value is controlled by React state via value and onChange.
3What is an uncontrolled component?medium
Answer: Input where DOM holds value; read/update via ref instead of state.
4Difference between preventDefault and stopPropagation?medium
Answer: preventDefault stops browser default; stopPropagation stops bubbling to parents.
5How to handle form submission?easy
Answer: Use onSubmit on form, call preventDefault, read state or FormData.
6Why use SyntheticEvent?medium
Answer: Cross-browser normalized wrapper around native events.
7How to pass parameters to event handlers?medium
Answer: Wrap in arrow function or bind—avoid calling handler immediately in JSX.
8How to handle multiple form fields?medium
Answer: Single state object updated by input name, or libraries like Formik/RHF.
9Can you use defaultValue with controlled inputs?hard
Answer: No—mixing controlled and uncontrolled causes warnings; pick one pattern.
10How to validate forms in React?medium
Answer: Validate in submit handler, on blur, or use schema libraries (Zod/Yup) with form libs.
11What is two-way binding in React?hard
Answer: React uses one-way flow; two-way effect is state + onChange, not automatic like Angular ngModel.
12How to reset a form?medium
Answer: Reset state to initial values or use key prop to remount form component.
13Handling select multiple options?hard
Answer: value as array and onChange reading selectedOptions.
14Why avoid inline anonymous functions in lists?hard
Answer: Can cause unnecessary child re-renders—stabilize with useCallback when needed.
15Accessible form best practice?medium
Answer: Use labels, aria attributes, focus management, and meaningful error messages.