React JS - Working With Forms
Mastering Form Handling in React JS

At Code Subtle, we empower aspiring web developers through personalized mentorship and engaging learning resources. Our community bridges the gap between theory and practice, guiding students from basics to advanced concepts. We offer expert mentorship and write interactive, user-friendly articles on all aspects of web development. Join us to learn, grow, and build your future in tech!
Form Elements
1. Working with input field in Forms
import { useState } from 'react'
import './App.css'
function App() {
const [username, setUsername]=useState("")
//default value is empty string
function handleUsername(e){
console.log(e.target.value);
setUsername(e.target.value)
}
return (
<>
<h2>Form Basics</h2>
<label htmlFor="username">User Name </label>
{/* we use htmlFor for label we can't use for
because it is reserved keyword in JS */}
<input type="text" id='username' value={username}
onChange={handleUsername}/>
<p>UserName: {username}</p>
</>
)
}
export default App
import { useState } from 'react'
import './App.css'
function App() {
const [username, setUsername]=useState("")
return (
<>
<h2>Form Basics</h2>
<label htmlFor="username">User Name </label>
<input type="text" id='username' value={username}
onChange={(e)=>setUsername(e.target.value)} />
<p>UserName: {username}</p>
</>
)
}
export default App
How It Works
useState hook:
const [username, setUsername] = useState("");useStatecreates a state variable calledusernameand sets its initial value to an empty string ("").setUsernameis a function that allows you to update the value ofusername.This is how React knows what the current value of
usernameis, and it will automatically re-render the component whenusernamechanges.
handleUsername function:
function handleUsername(e) { console.log(e.target.value); setUsername(e.target.value); }erepresents the event object, ande.targetrefers to the input field that triggered the event.e.target.valuegets the current value from the input field (whatever the user is typing).setUsername(e.target.value)updates theusernamestate with the new input value.Every time the input value changes, the
usernamestate gets updated, and the component re-renders to display the updated value.
JSX (Rendering the UI):
<input type="text" id='username' value={username} onChange={handleUsername}/> <p>UserName: {username}</p>The
inputfield has itsvaluetied to theusernamestate. This means whatever is inusernamewill be displayed in the input field.The
onChange={handleUsername}triggers thehandleUsernamefunction whenever the user types something.The
<p>tag displays the currentusernamevalue as text right below the input field.
Flow:
Initially,
usernameis an empty string ("").When the user types in the input box, the
handleUsernamefunction is triggered, updatingusernamewith the new input value.React re-renders the component to show the updated username both in the input field and in the
<p>element.
// Multiple Input Field Using a Button
import { useState } from "react";
import "./App.css";
function App() {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("")
function handleSubmit(e) {
e.preventDefault();
console.log('Hey! ' ,username);
}
return (
<>
<h2>Form Basics</h2>
<form onSubmit={handleSubmit}>
<label htmlFor="username">User Name </label>
<input
type="text"
id="username"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
<input
type="password"
id="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button type="submit">Submit</button>
</form>
<p>UserName: {username}</p>
</>
);
}
export default App;
2. For Radio Buttons:
// Radio Button
import { useState } from 'react'
function App() {
const [gender, setGender] = useState('')
return (
<>
<input
type="radio"
checked={gender === "male"}
onChange={() => {
setGender("male");
}}
/>
<label htmlFor="male">Male</label>
<input
type="radio"
checked={gender === "female"}
onChange={() => {
setGender("female");
}}
/>
<label htmlFor="female">Female</label>
<input
type="radio"
checked={gender === "others"}
onChange={() => {
setGender("others");
}}
/>
<label htmlFor="others">Others</label>
</>
);
}
export default App
How it works
useState hook:
const [gender, setGender] = useState('');This initializes the
genderstate as an empty string ('').setGenderis a function used to update thegenderstate whenever the user selects a radio button.
Radio buttons: Each radio button's
checkedattribute is linked to the current value of thegenderstate, and when clicked, the state is updated with the selected gender:<input type="radio" checked={gender === "male"} onChange={() => { setGender("male"); }} /> <label htmlFor="male">Male</label>The
checked={gender === "male"}ensures that the radio button for "Male" is selected only when thegenderstate is"male".onChange={() => { setGender("male"); }}updates thegenderstate to"male"when the user selects this radio button.
Similarly, for "Female" and "Others":
<input
type="radio"
checked={gender === "female"}
onChange={() => { setGender("female"); }}
/>
<label htmlFor="female">Female</label>
<input
type="radio"
checked={gender === "others"}
onChange={() => { setGender("others"); }}
/>
<label htmlFor="others">Others</label>
How it behaves:
Only one radio button can be selected at a time. When a user clicks on a radio button, the
genderstate is updated (e.g.,"male","female", or"others"), and the corresponding radio button becomes checked.The
checkedattribute for each radio button ensures that it visually reflects the current state.
3. Handling Multiple Inputs:
import { useState } from "react";
function HandleMultipleInputs() {
const [formData, setFormData] = useState({
firstName: "",
lastName: "",
email: "",
userName: "",
password: "",
confirmPassword: "",
phone: "",
address: "",
});
const handleSubmit = (e) => {
e.preventDefault();
console.log(formData);
};
const handleChange = (e) => {
setFormData((prevState) => {
return { ...prevState, [e.target.id]: e.target.value };
});
};
const {
firstName,
lastName,
email,
userName,
password,
confirmPassword,
phone,
address,
} = formData;
return (
<form onSubmit={handleSubmit} style={{ padding: "1rem" }}>
<div className="formGroup">
<label htmlFor="firstName">firstName</label>
<br />
<input
type="text"
name="firstName"
id="firstName"
value={firstName}
onChange={handleChange}
/>
</div>
<div className="formGroup">
<label htmlFor="lastName">lastName</label>
<br />
<input
type="text"
name="lastName"
id="lastName"
value={lastName}
onChange={handleChange}
/>
</div>
<div className="formGroup">
<label htmlFor="userName">userName</label>
<br />
<input
type="text"
name="userName"
id="userName"
value={userName}
onChange={handleChange}
/>
</div>
<div className="formGroup">
<label htmlFor="email">email</label>
<br />
<input
type="email"
name="email"
id="email"
onChange={handleChange}
value={email}
/>
</div>
<div className="formGroup">
<label htmlFor="password">password</label>
<br />
<input
type="password"
name="password"
id="password"
value={password}
onChange={handleChange}
/>
</div>
<div className="formGroup">
<label htmlFor="confirmPassword">confirm Password</label>
<br />
<input
type="password"
name="confirmPassword"
id="confirmPassword"
value={confirmPassword}
onChange={handleChange}
/>
</div>
<div className="formGroup">
<label htmlFor="phone">phone</label>
<br />
<input
type="number"
name="phone"
id="phone"
value={phone}
onChange={handleChange}
/>
</div>
<div className="formGroup">
<label htmlFor="address">address</label>
<br />
<input
type="text"
name="address"
id="address"
value={address}
onChange={handleChange}
/>
</div>
<input type="submit" value="sign up" style={{ marginTop: "1rem" }} />
</form>
);
}
export default HandleMultipleInputs;
How it works
State Initialization:
const [formData, setFormData] = useState({ firstName: "", lastName: "", email: "", userName: "", password: "", confirmPassword: "", phone: "", address: "", });The form data is stored in an object
formDatawith keys for each form field (e.g.,firstName,lastName,email).setFormDatais used to update this object when any of the form fields change.
handleChange function:
const handleChange = (e) => { setFormData((prevState) => { return { ...prevState, [e.target.id]: e.target.value }; }); };This function is called whenever a user types in any of the form fields.
e.target.idrefers to theidof the input field that triggered the event, ande.target.valueis the new value entered.setFormDataupdates the corresponding field in theformDataobject while keeping the other fields unchanged (...prevStatespreads the previous state to avoid overwriting the entire object).
handleSubmit function:
const handleSubmit = (e) => { e.preventDefault(); console.log(formData); };This function prevents the default form submission behavior (which would refresh the page) and logs the
formDatato the console when the form is submitted.In a real application, this is where you would handle the submission, like sending the data to a backend.
JSX (Rendering the form): Each input field corresponds to a key in the
formDataobject, and its value is controlled by React:<input type="text" name="firstName" id="firstName" value={firstName} onChange={handleChange} />The
idof each input matches the key in theformDataobject (e.g.,id="firstName").value={firstName}ensures that the input field reflects the current state.onChange={handleChange}updates theformDatawhen the user types something.
The same pattern applies to all the other form fields (last name, email, phone, etc.).
Submit Button:
<input type="submit" value="sign up" style={{ marginTop: "1rem" }} />- A submit button is provided at the bottom of the form. When clicked, it triggers the
handleSubmitfunction.
- A submit button is provided at the bottom of the form. When clicked, it triggers the
Key Concepts:
Single State Object: All form fields are managed using one state object (
formData), making the code more concise and scalable.Dynamic Updates: The
handleChangefunction dynamically updates the form fields based on theidof the input element, making it reusable for all fields.Controlled Components: The form inputs are controlled components because their values are managed by React's state.
useRef Hook
useRef always returns single object and it only has current value of the object. In useRef the component value doesn't re-render. Change of ref does not trigger re-render of the component.
Form Input Using useRef
import React, { useRef } from "react";
function ExamplUseRef() {
console.log("component Rendered");
const username = useRef("Vitthal");
const handleName = () => {
username.current = "Korvan";
console.log(username);
};
return (
<>
<h1>Hello, {username.current}</h1>
<button onClick={handleName}>Change UserName</button>
</>
);
}
export default ExamplUseRef;
import React, { useRef } from "react";
function DOMUseRef() {
const h1ref = useRef();
const handleClick = () => {
const h1Element = h1ref.current;
console.log(h1Element);
h1Element.textContent = "Hey! Vitthal";
h1Element.style.backgroundColor = "blue";
h1Element.style.color = "white";
};
return (
<>
<h1 ref={h1ref}>Hello! World</h1>
<button onClick={handleClick}> Change Content</button>
</>
);
}
export default DOMUseRef;
How it works
useRef Hook:
const username = useRef("Vitthal");useRefis initialized with"Vitthal", meaning theusername.currentis set to"Vitthal".Unlike
useState, changing the value of auseRefvariable does not trigger a re-render. Instead, the value is simply stored and persists across renders.username.currentholds the current value ("Vitthal"at the start).
handleName function:
const handleName = () => { username.current = "Korvan"; console.log(username); };This function changes the value of
username.currentto"Korvan".Since
useRefdoes not trigger a re-render, the UI won't update whenusername.currentis changed, but the value stored insideusernamewill be updated.console.log(username)will show the updatedcurrentvalue, but the displayed username in the UI will remain the same unless a re-render happens.
JSX (Rendering the UI):
<h1>Hello, {username.current}</h1> <button onClick={handleName}>Change UserName</button>Initially,
"Vitthal"will be displayed in the<h1>tag asusername.currentis"Vitthal".Clicking the "Change UserName" button will change
username.currentto"Korvan", but the displayed name won't update becauseuseRefdoes not cause a re-render.
Important Concepts
useRef vs. useState:
useStatecauses a component to re-render when its value is updated.useRefdoes not cause a re-render when updated. It is mainly used for persisting values between renders or for directly interacting with DOM elements (e.g., focusing on an input).
No Re-render:
Although the
username.currentis updated to"Korvan", the component doesn’t re-render, so"Vitthal"will still be displayed.If you want to re-render the component when the value changes, you should use
useStateinstead ofuseRef.
Uncontrolled Input Using UseRef:
import React, { useRef } from "react";
export function HandleInputUseRef() {
const usernameRef = useRef()
const passwordRef = useRef()
const handleSubmit = (e)=>{
e.preventDefault()
const usernameInput =usernameRef.current
const passwordInput = passwordRef.current
console.log(usernameInput.value);
console.log(passwordInput.value);
}
return (
<form onSubmit={handleSubmit}>
<label htmlFor="username">UserName</label>
<br />
<input type="text" id="username" ref={usernameRef}/>
<br />
<label htmlFor="password">password</label>
<br />
<input type="text" id="password" ref={passwordRef}/>
<br />
<button>Submit</button>
</form>
);
}
How It Works
1. Imports and useRef Hook
import React, { useRef } from "react";
- You import
Reactand theuseRefhook.useRefis a hook in React that allows you to directly access and manipulate DOM elements or persist values without causing re-renders. In this case, it's being used to reference the input fields in the form.
2. Creating References with useRef
const usernameRef = useRef(null);
const passwordRef = useRef(null);
useRef(null)creates references for the username and password inputs, initially set tonullbecause the elements don't exist in the DOM until they are rendered. Once rendered,useRefwill store the reference to the input elements.
3. Form Submit Handler
const handleSubmit = (e) => {
e.preventDefault();
const usernameInput = usernameRef.current;
const passwordInput = passwordRef.current;
console.log(usernameInput.value);
console.log(passwordInput.value);
};
handleSubmitis the function triggered when the form is submitted.e.preventDefault()prevents the default form submission behavior (reloading the page).usernameRef.currentandpasswordRef.currentaccess the actual DOM elements for the username and password inputs.usernameInput.valueandpasswordInput.valuefetch the values entered by the user.The values are logged to the console.
4. Form JSX Structure
<form onSubmit={handleSubmit}>
<label htmlFor="username">UserName</label>
<br />
<input type="text" id="username" ref={usernameRef} />
<br />
<label htmlFor="password">Password</label>
<br />
<input type="password" id="password" ref={passwordRef} />
<br />
<button>Submit</button>
</form>
The form contains two labeled input fields: one for the username and one for the password.
Each
inputhas itsrefattribute set tousernameRefandpasswordRef, linking the DOM element to theuseRefhook.The
onSubmitevent is tied to thehandleSubmitfunction, so when the user submits the form, the entered values are logged to the console.
Key Points:
useRef: It provides a way to reference DOM elements without causing re-renders. You use it to store references to theusernameandpasswordinputs.Form Submission: On submission,
handleSubmitaccesses the current values of these inputs and logs them.Direct DOM Manipulation: Unlike
useState, usinguseRefdoes not cause the component to re-render when the values are changed or accessed.
GitHub Code : Working With Forms






