React Events & Forms
onClick, onChange, controlled components, and building interactive forms
Events
onClick
onChange
Controlled Forms
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
Aspect Regular DOM / HTML React
Naming Lowercase (onclick) CamelCase (onClick)
Handler Value String of function name Actual JavaScript function reference
Default Behavior return falsepreventDefault() explicitly
Event Object Native browser event SyntheticEvent 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
JSX function 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
JSX function 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
JSX function 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:
Property Description
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
JSX const 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
JSX function 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
JSX function 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
JSX function 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
JSX const handleChange = (event) => {
const { name, value, type, checked } = event.target;
setFormData(prev => ({ ...prev, [name]: value }));
};
JSX const 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
JSX const handleChange = (event) => {
const newEmail = event.target.value;
setEmail(newEmail);
validateEmail(newEmail); // Validate on every keystroke
};
6. Form Inputs in React
React supports all HTML input types: text, password, email, number, tel, url, search, color, date, time, file, and more.
JSX const handleChange = (event) => {
const { name, value, type, checked } = event.target;
setFormData(prev => ({
...prev,
[name]: type === "checkbox" ? checked : value
}));
};
JSX const 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
JSX const 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
Aspect Controlled Uncontrolled
Value source React state DOM itself
Access value From state Using ref
Validation Real-time, easy More 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.
JSX function 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
JSX function 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
JSX const 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)
JSX function 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.
JSX function 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
JSX function 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
Mistake Why It's Wrong Correct Way
Forgetting preventDefault() Page reloads, state resets Always call in form onSubmit
value without onChangeInput becomes read-only Always provide onChange
No loading states Multiple submissions Disable button during async
Validate password on every keystroke Premature errors Validate 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:
A onClick
B onclick
C ONCLICK
D click-handler
Explanation: DOM uses lowercase; React uses onClick.
2
To prevent default form submit you call:
A e.preventDefault() in handler
B return false only in HTML
C stopPropagation only
D alert()
Explanation: Handle submit and call preventDefault.
3
Passing arguments to handlers often uses:
A Arrow function wrapper () => handle(id)
B handle(id) directly in onClick attribute
C global variables only
D innerHTML
Explanation: onClick={() => handle(id)} avoids immediate invocation.
4
A controlled input has:
A value bound to state and onChange updater
B No onChange
C ref only always
D defaultValue only in production
Explanation: React state is single source of truth.
5
onChange on text input receives:
A Synthetic event with target.value
B Only mouse coordinates
C Promise
D CSS class
Explanation: e.target.value reads input text.
6
Synthetic events in React:
A Wrap native events for cross-browser consistency
B Disable all events
C Are slower than native always
D Replace state
Explanation: React normalizes event behavior.
7
Checkbox controlled pattern uses:
A checked + onChange
B value only
C type=text
D disabled always
Explanation: Boolean checked state for checkboxes.
8
Select dropdown controlled value comes from:
A state via value prop on select
B document.cookie
C props only immutable
D CSS
Explanation: <select value={city} onChange={...}>.
9
Form submit handler is attached with:
A onSubmit on form element
B onClick on body only
C onLoad
D onResize
Explanation: Use onSubmit not button click for forms.
10
e.stopPropagation() prevents:
A Event bubbling to parent elements
B Default browser action always
C State updates
D Re-renders
Explanation: preventDefault vs stopPropagation serve different purposes.
10 Advanced React Events & Forms MCQs
1
Uncontrolled inputs use:
A ref to read DOM value
B value + onChange only
C Context only
D Redux only
Explanation: useRef + ref on input for uncontrolled pattern.
2
Multiple inputs one handler pattern:
A name attribute + setState from e.target.name
B Separate component per key always
C No state
D Only uncontrolled
Explanation: Dynamic key: [e.target.name]: e.target.value.
3
React 17+ attaches events to:
A Root container (delegation)
B Every DOM node individually
C window only in IE
D Shadow DOM only
Explanation: Delegation changed from document in React 17.
4
Passing e.persist() was needed when:
A Using async code with pooled SyntheticEvent (legacy)
B Using hooks
C Using Vite
D Using TypeScript
Explanation: React 17+ removed event pooling.
5
File input is often uncontrolled because:
A File path cannot be set via value for security
B Files use text value prop
C React forbids files
D onChange not supported
Explanation: Read files from ref or event target.files.
6
Debouncing search input typically uses:
A setTimeout/clearTimeout or custom hook
B preventDefault only
C dangerouslySetInnerHTML
D Strict Mode off
Explanation: Debounce limits API calls while typing.
7
Form libraries like React Hook Form optimize by:
A Reducing re-renders via uncontrolled refs
B Removing JSX
C Disabling validation
D Using jQuery
Explanation: Less state churn on every keystroke.
8
Keyboard Enter in textarea vs form:
A Enter may newline in textarea; form may submit on Enter
B Always submits
C Never fires events
D Blocked by React
Explanation: Handle onKeyDown if custom behavior needed.
9
Accessibility: label htmlFor connects to:
A input id for screen readers
B CSS class only
C router path
D npm script
Explanation: Associate labels with inputs via id.
10
Controlled component pitfall with rapid typing:
A Lag if parent re-render is expensive—optimize or local state
B Always faster than native
C Cannot use state
D Breaks JSX
Explanation: Profile and defer heavy parent updates.
Check All Answers
15 React Events & Forms Interview Questions & Answers
Easy
Medium
Hard
1 How do you handle clicks in React?easy
Answer: Attach onClick={handler} to JSX elements with camelCase event names.
2 What is a controlled component?easy
Answer: Form element whose value is controlled by React state via value and onChange.
3 What is an uncontrolled component?medium
Answer: Input where DOM holds value; read/update via ref instead of state.
4 Difference between preventDefault and stopPropagation?medium
Answer: preventDefault stops browser default; stopPropagation stops bubbling to parents.
5 How to handle form submission?easy
Answer: Use onSubmit on form, call preventDefault, read state or FormData.
6 Why use SyntheticEvent?medium
Answer: Cross-browser normalized wrapper around native events.
7 How to pass parameters to event handlers?medium
Answer: Wrap in arrow function or bind—avoid calling handler immediately in JSX.
8 How to handle multiple form fields?medium
Answer: Single state object updated by input name, or libraries like Formik/RHF.
9 Can you use defaultValue with controlled inputs?hard
Answer: No—mixing controlled and uncontrolled causes warnings; pick one pattern.
10 How to validate forms in React?medium
Answer: Validate in submit handler, on blur, or use schema libraries (Zod/Yup) with form libs.
11 What is two-way binding in React?hard
Answer: React uses one-way flow; two-way effect is state + onChange, not automatic like Angular ngModel.
12 How to reset a form?medium
Answer: Reset state to initial values or use key prop to remount form component.
13 Handling select multiple options?hard
Answer: value as array and onChange reading selectedOptions.
14 Why avoid inline anonymous functions in lists?hard
Answer: Can cause unnecessary child re-renders—stabilize with useCallback when needed.
15 Accessible form best practice?medium
Answer: Use labels, aria attributes, focus management, and meaningful error messages.