Skillversitas

Forms

Controlled vs Uncontrolled Components

React offers two approaches for managing form inputs:

Approach Description
Controlled The input value is controlled by React state. Recommended.
Uncontrolled The input value is managed by the DOM itself.

Controlled Components

Every input has a value bound to React state. Each change is updated into state.

import { useState } from 'react';

function FormLogin() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  return (
    <form onSubmit={(e) => { e.preventDefault(); console.log(email, password); }}>
      <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">Log In</button>
    </form>
  );
}

Uncontrolled Components

Use useRef to access the DOM value directly without state on every keystroke.

import { useRef } from 'react';

function FormUncontrolled() {
  const nameRef = useRef();

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log("Name:", nameRef.current.value);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input ref={nameRef} type="text" placeholder="Name" />
      <button type="submit">Send</button>
    </form>
  );
}

Text Inputs and Textareas

function FormProfile() {
  const [form, setForm] = useState({ name: "", bio: "" });

  const handleChange = (e) => {
    setForm({ ...form, [e.target.name]: e.target.value });
  };

  return (
    <form>
      <input
        name="name"
        value={form.name}
        onChange={handleChange}
        placeholder="Full name"
      />
      <textarea
        name="bio"
        value={form.bio}
        onChange={handleChange}
        placeholder="Tell us about yourself"
      />
      <p>{form.bio.length}/200 characters</p>
    </form>
  );
}

Select (Dropdown)

function FormSelect() {
  const [language, setLanguage] = useState("id");

  return (
    <select value={language} onChange={(e) => setLanguage(e.target.value)}>
      <option value="id">Indonesia</option>
      <option value="en">English</option>
      <option value="ja">日本語</option>
    </select>
  );
}

Checkbox

function FormCheckbox() {
  const [agreed, setAgreed] = useState(false);

  return (
    <label>
      <input
        type="checkbox"
        checked={agreed}
        onChange={(e) => setAgreed(e.target.checked)}
      />
      I agree to the terms and conditions
    </label>
  );
}

Radio Button

function FormRadio() {
  const [gender, setGender] = useState("male");

  return (
    <div>
      <label>
        <input
          type="radio"
          name="gender"
          value="male"
          checked={gender === "male"}
          onChange={(e) => setGender(e.target.value)}
        />
        Male
      </label>
      <label>
        <input
          type="radio"
          name="gender"
          value="female"
          checked={gender === "female"}
          onChange={(e) => setGender(e.target.value)}
        />
        Female
      </label>
      <p>Selection: {gender}</p>
    </div>
  );
}

Form Submission Handler

function RegistrationForm() {
  const [form, setForm] = useState({ name: "", email: "", agree: false });

  const handleChange = (e) => {
    const { name, value, type, checked } = e.target;
    setForm({ ...form, [name]: type === "checkbox" ? checked : value });
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    if (!form.name || !form.email) {
      alert("Name and email are required!");
      return;
    }
    if (!form.agree) {
      alert("You must agree to the terms!");
      return;
    }
    console.log("Data submitted:", form);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input name="name" value={form.name} onChange={handleChange} placeholder="Name" />
      <input name="email" value={form.email} onChange={handleChange} placeholder="Email" />
      <label>
        <input
          name="agree"
          type="checkbox"
          checked={form.agree}
          onChange={handleChange}
        />
        I agree
      </label>
      <button type="submit">Register</button>
    </form>
  );
}

export default RegistrationForm;

Summary

Controlled components are the standard approach in React for managing forms. By binding every input to state, you get full control over the data, validation, and form behavior. Combine it with event handling for a complete form experience.

Congratulations! You have finished the React fundamentals. Next steps: learn React Router for navigation, Redux or Context API for state management, and start building real projects.