React JS - Working With Forms
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("");
useState
creates a state variable calledusername
and sets its initial value to an empty string (""
).setUsername
is a function that allows you to update the value ofusername
.This is how React knows what the current value of
username
is, and it will automatically re-render the component whenusername
changes.
handleUsername function:
function handleUsername(e) { console.log(e.target.value); setUsername(e.target.value); }
e
represents the event object, ande.target
refers to the input field that triggered the event.e.target
.value
gets the current value from the input field (whatever the user is typing).setUsername(
e.target
.value)
updates theusername
state with the new input value.Every time the input value changes, the
username
state 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
input
field has itsvalue
tied to theusername
state. This means whatever is inusername
will be displayed in the input field.The
onChange={handleUsername}
triggers thehandleUsername
function whenever the user types something.The
<p>
tag displays the currentusername
value as text right below the input field.
Flow:
Initially,
username
is an empty string (""
).When the user types in the input box, the
handleUsername
function is triggered, updatingusername
with 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
gender
state as an empty string (''
).setGender
is a function used to update thegender
state whenever the user selects a radio button.
Radio buttons: Each radio button's
checked
attribute is linked to the current value of thegender
state, 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 thegender
state is"male"
.onChange={() => { setGender("male"); }}
updates thegender
state 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
gender
state is updated (e.g.,"male"
,"female"
, or"others"
), and the corresponding radio button becomes checked.The
checked
attribute 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
formData
with keys for each form field (e.g.,firstName
,lastName
,email
).setFormData
is 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.id
refers to theid
of the input field that triggered the event, ande.target
.value
is the new value entered.setFormData
updates the corresponding field in theformData
object while keeping the other fields unchanged (...prevState
spreads 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
formData
to 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
formData
object, and its value is controlled by React:<input type="text" name="firstName" id="firstName" value={firstName} onChange={handleChange} />
The
id
of each input matches the key in theformData
object (e.g.,id="firstName"
).value={firstName}
ensures that the input field reflects the current state.onChange={handleChange}
updates theformData
when 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
handleSubmit
function.
- 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
handleChange
function dynamically updates the form fields based on theid
of 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");
useRef
is initialized with"Vitthal"
, meaning theusername.current
is set to"Vitthal"
.Unlike
useState
, changing the value of auseRef
variable does not trigger a re-render. Instead, the value is simply stored and persists across renders.username.current
holds the current value ("Vitthal"
at the start).
handleName function:
const handleName = () => { username.current = "Korvan"; console.log(username); };
This function changes the value of
username.current
to"Korvan"
.Since
useRef
does not trigger a re-render, the UI won't update whenusername.current
is changed, but the value stored insideusername
will be updated.console.log(username)
will show the updatedcurrent
value, 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.current
is"Vitthal"
.Clicking the "Change UserName" button will change
username.current
to"Korvan"
, but the displayed name won't update becauseuseRef
does not cause a re-render.
Important Concepts
useRef vs. useState:
useState
causes a component to re-render when its value is updated.useRef
does 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.current
is 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
useState
instead 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
React
and theuseRef
hook.useRef
is 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 tonull
because the elements don't exist in the DOM until they are rendered. Once rendered,useRef
will 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);
};
handleSubmit
is the function triggered when the form is submitted.e.preventDefault()
prevents the default form submission behavior (reloading the page).usernameRef.current
andpasswordRef.current
access the actual DOM elements for the username and password inputs.usernameInput.value
andpasswordInput.value
fetch 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
input
has itsref
attribute set tousernameRef
andpasswordRef
, linking the DOM element to theuseRef
hook.The
onSubmit
event is tied to thehandleSubmit
function, 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 theusername
andpassword
inputs.Form Submission: On submission,
handleSubmit
accesses the current values of these inputs and logs them.Direct DOM Manipulation: Unlike
useState
, usinguseRef
does not cause the component to re-render when the values are changed or accessed.
GitHub Code : Working With Forms
Subscribe to my newsletter
Read articles from Vitthal Korvan directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Vitthal Korvan
Vitthal Korvan
π Hello, World! I'm Vitthal Korvan π As a passionate front-end web developer, I transform digital landscapes into captivating experiences. you'll find me exploring the intersection of technology and art, sipping on a cup of coffee, or contributing to the open-source community. Life is an adventure, and I bring that spirit to everything I do.