Falytom logoFALYTOM
Games
ToolsUI ComponentsServicesProductsAbout
LoginSign Up
menu
  1. Home
  2. /Web Development
  3. /React
  4. /Forms In React
Your Progress0%
0 of 42 completed

React Topics

Getting Started

  • What is React?
  • React vs Vanilla JavaScript
  • Setting Up Your Environment
  • Your First React App

JSX Fundamentals

  • Introduction to JSX
  • JSX Expressions and Variables
  • Conditional Rendering
  • Lists and Keys
  • Styling in JSX

Components Basics

  • Function Components
  • Props
  • Children Prop
  • Props Destructuring
  • Component Composition

State Management

  • Introduction to State
  • useState Hook
  • State Updates and Re-renders
  • Multiple State Variables
  • State Best Practices

Events and Interactivity

  • Handling Events
  • Event Objects
  • Forms in React
  • Form Validation

Side Effects and Data

  • Introduction to useEffect
  • Data Fetching
  • Cleanup Functions
  • Dependency Arrays

Advanced Hooks

  • useRef Hook
  • useContext Hook
  • useMemo Hook
  • useCallback Hook

React Patterns

  • Custom Hooks
  • Higher-Order Components
  • Render Props Pattern

React Router

  • Introduction to React Router
  • Routes and Navigation
  • Dynamic Routes and Parameters

Best Practices

  • Component Organization
  • Performance Optimization
  • Error Handling
  • Testing React Components

Real World Project

  • Building a Complete App

Forms in React

Building controlled form components

Forms are everywhere in web applications - login screens, registration pages, search boxes, settings panels, and more. In React, forms work a bit differently than in HTML. You'll learn about controlled components, where React state controls form inputs, giving you complete power over form behavior. You'll also learn efficient patterns for handling multiple inputs, form submission, and building complex forms that scale. Let's master React forms!

Controlled Components

In React, form inputs should be controlled components - their values are controlled by React state:

Uncontrolled (HTML Way)

uncontrolled.html
<!-- HTML - DOM is the source of truth -->
<input type="text" id="username" />

<script>
  // Read value from DOM when needed
  const username = document.getElementById('username').value
</script>

<!-- Problem: React doesn't know about changes
     Can't easily validate, transform, or sync with other components -->

Controlled (React Way)

controlled.jsx
function Form() {
  // React state is the source of truth
  const [username, setUsername] = React.useState('')
  
  return (
    <input
      type="text"
      value={username}              // React controls the value
      onChange={(e) => setUsername(e.target.value)}  // Update state on change
    />
  )
}

// Benefits:
// - React knows the value at all times
// - Easy to validate, transform, or sync
// - Can clear input: setUsername('')
// - Can set programmatically: setUsername('admin')

Controlled Component Rules:

  1. Store value in state
  2. Set input's value prop to state
  3. Update state in onChange handler
  4. State is the single source of truth

Basic Form Inputs

Text Input

text-input.jsx
function TextInput() {
  const [name, setName] = React.useState('')
  
  return (
    <div>
      <label>
        Name:
        <input
          type="text"
          value={name}
          onChange={(e) => setName(e.target.value)}
        />
      </label>
      <p>You entered: {name}</p>
    </div>
  )
}

Email Input

email-input.jsx
function EmailInput() {
  const [email, setEmail] = React.useState('')
  
  return (
    <div>
      <label>
        Email:
        <input
          type="email"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          placeholder="user@example.com"
        />
      </label>
    </div>
  )
}

Password Input

password-input.jsx
function PasswordInput() {
  const [password, setPassword] = React.useState('')
  const [showPassword, setShowPassword] = React.useState(false)
  
  return (
    <div>
      <label>
        Password:
        <input
          type={showPassword ? 'text' : 'password'}
          value={password}
          onChange={(e) => setPassword(e.target.value)}
        />
      </label>
      <button type="button" onClick={() => setShowPassword(!showPassword)}>
        {showPassword ? 'Hide' : 'Show'}
      </button>
    </div>
  )
}

Number Input

number-input.jsx
function NumberInput() {
  const [age, setAge] = React.useState(0)
  
  const handleChange = (e) => {
    // Convert to number
    setAge(Number(e.target.value))
  }
  
  return (
    <div>
      <label>
        Age:
        <input
          type="number"
          value={age}
          onChange={handleChange}
          min="0"
          max="120"
        />
      </label>
    </div>
  )
}

Textarea

textarea.jsx
function TextareaInput() {
  const [message, setMessage] = React.useState('')
  
  return (
    <div>
      <label>
        Message:
        <textarea
          value={message}
          onChange={(e) => setMessage(e.target.value)}
          rows={4}
          placeholder="Enter your message..."
        />
      </label>
      <p>Character count: {message.length}</p>
    </div>
  )
}

// Note: In React, textarea uses value prop (not children like HTML)

Checkboxes and Radio Buttons

Single Checkbox

single-checkbox.jsx
function SingleCheckbox() {
  const [isChecked, setIsChecked] = React.useState(false)
  
  return (
    <label>
      <input
        type="checkbox"
        checked={isChecked}  // Use 'checked', not 'value'
        onChange={(e) => setIsChecked(e.target.checked)}
      />
      I agree to the terms and conditions
    </label>
  )
}

// IMPORTANT: Checkboxes use 'checked' prop and e.target.checked

Multiple Checkboxes

multiple-checkboxes.jsx
function MultipleCheckboxes() {
  const [interests, setInterests] = React.useState([])
  
  const handleChange = (interest) => {
    if (interests.includes(interest)) {
      // Remove if already selected
      setInterests(interests.filter(i => i !== interest))
    } else {
      // Add if not selected
      setInterests([...interests, interest])
    }
  }
  
  return (
    <div>
      <p>Select your interests:</p>
      <label>
        <input
          type="checkbox"
          checked={interests.includes('coding')}
          onChange={() => handleChange('coding')}
        />
        Coding
      </label>
      <label>
        <input
          type="checkbox"
          checked={interests.includes('design')}
          onChange={() => handleChange('design')}
        />
        Design
      </label>
      <label>
        <input
          type="checkbox"
          checked={interests.includes('music')}
          onChange={() => handleChange('music')}
        />
        Music
      </label>
      <p>Selected: {interests.join(', ')}</p>
    </div>
  )
}

Radio Buttons

radio-buttons.jsx
function RadioButtons() {
  const [size, setSize] = React.useState('medium')
  
  return (
    <div>
      <p>Select size:</p>
      <label>
        <input
          type="radio"
          name="size"
          value="small"
          checked={size === 'small'}
          onChange={(e) => setSize(e.target.value)}
        />
        Small
      </label>
      <label>
        <input
          type="radio"
          name="size"
          value="medium"
          checked={size === 'medium'}
          onChange={(e) => setSize(e.target.value)}
        />
        Medium
      </label>
      <label>
        <input
          type="radio"
          name="size"
          value="large"
          checked={size === 'large'}
          onChange={(e) => setSize(e.target.value)}
        />
        Large
      </label>
      <p>Selected: {size}</p>
    </div>
  )
}

// Radio buttons: all have same 'name', different 'value'

Select Dropdown

Basic Select

select-basic.jsx
function SelectBasic() {
  const [country, setCountry] = React.useState('us')
  
  return (
    <div>
      <label>
        Country:
        <select value={country} onChange={(e) => setCountry(e.target.value)}>
          <option value="us">United States</option>
          <option value="uk">United Kingdom</option>
          <option value="ca">Canada</option>
          <option value="au">Australia</option>
        </select>
      </label>
      <p>Selected: {country}</p>
    </div>
  )
}

// Select uses value prop on <select>, not on <option>

Multi-Select

select-multi.jsx
function MultiSelect() {
  const [languages, setLanguages] = React.useState([])
  
  const handleChange = (e) => {
    const options = Array.from(e.target.selectedOptions)
    const values = options.map(option => option.value)
    setLanguages(values)
  }
  
  return (
    <div>
      <label>
        Languages:
        <select multiple value={languages} onChange={handleChange}>
          <option value="js">JavaScript</option>
          <option value="py">Python</option>
          <option value="rb">Ruby</option>
          <option value="go">Go</option>
        </select>
      </label>
      <p>Selected: {languages.join(', ')}</p>
      <p className="note">Hold Ctrl/Cmd to select multiple</p>
    </div>
  )
}

Handling Multiple Inputs

Pattern 1: Individual State Variables

multiple-individual.jsx
function Form() {
  const [firstName, setFirstName] = React.useState('')
  const [lastName, setLastName] = React.useState('')
  const [email, setEmail] = React.useState('')
  
  const handleSubmit = (e) => {
    e.preventDefault()
    console.log({ firstName, lastName, email })
  }
  
  return (
    <form onSubmit={handleSubmit}>
      <input
        value={firstName}
        onChange={(e) => setFirstName(e.target.value)}
        placeholder="First Name"
      />
      <input
        value={lastName}
        onChange={(e) => setLastName(e.target.value)}
        placeholder="Last Name"
      />
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Email"
      />
      <button type="submit">Submit</button>
    </form>
  )
}

// Simple but verbose for many inputs

Pattern 2: Single State Object (Recommended)

multiple-object.jsx
function Form() {
  const [formData, setFormData] = React.useState({
    firstName: '',
    lastName: '',
    email: '',
    age: 0,
    subscribe: false
  })
  
  const handleChange = (e) => {
    const { name, value, type, checked } = e.target
    setFormData({
      ...formData,
      [name]: type === 'checkbox' ? checked : value
    })
  }
  
  const handleSubmit = (e) => {
    e.preventDefault()
    console.log(formData)
  }
  
  return (
    <form onSubmit={handleSubmit}>
      <input
        name="firstName"
        value={formData.firstName}
        onChange={handleChange}
        placeholder="First Name"
      />
      <input
        name="lastName"
        value={formData.lastName}
        onChange={handleChange}
        placeholder="Last Name"
      />
      <input
        name="email"
        type="email"
        value={formData.email}
        onChange={handleChange}
        placeholder="Email"
      />
      <input
        name="age"
        type="number"
        value={formData.age}
        onChange={handleChange}
      />
      <label>
        <input
          name="subscribe"
          type="checkbox"
          checked={formData.subscribe}
          onChange={handleChange}
        />
        Subscribe to newsletter
      </label>
      <button type="submit">Submit</button>
    </form>
  )
}

// Single handler for all inputs - scales well!
// Key: Each input needs a 'name' attribute

💡 Generic Handler Pattern

The generic handler pattern works because:
1. Each input has a name attribute matching the state key
2. We use [name] computed property to update the right key
3. We check type to handle checkboxes differently

This pattern is perfect for forms with many inputs!

Form Submission

form-submission.jsx
function LoginForm() {
  const [formData, setFormData] = React.useState({
    email: '',
    password: '',
    rememberMe: false
  })
  const [isSubmitting, setIsSubmitting] = React.useState(false)
  
  const handleChange = (e) => {
    const { name, value, type, checked } = e.target
    setFormData({
      ...formData,
      [name]: type === 'checkbox' ? checked : value
    })
  }
  
  const handleSubmit = async (e) => {
    e.preventDefault()  // ALWAYS prevent default!
    
    setIsSubmitting(true)
    
    try {
      // Simulate API call
      await fetch('/api/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(formData)
      })
      
      console.log('Login successful!')
      
      // Clear form after success
      setFormData({ email: '', password: '', rememberMe: false })
    } catch (error) {
      console.error('Login failed:', error)
    } finally {
      setIsSubmitting(false)
    }
  }
  
  return (
    <form onSubmit={handleSubmit}>
      <input
        name="email"
        type="email"
        value={formData.email}
        onChange={handleChange}
        placeholder="Email"
        required
      />
      <input
        name="password"
        type="password"
        value={formData.password}
        onChange={handleChange}
        placeholder="Password"
        required
      />
      <label>
        <input
          name="rememberMe"
          type="checkbox"
          checked={formData.rememberMe}
          onChange={handleChange}
        />
        Remember me
      </label>
      <button type="submit" disabled={isSubmitting}>
        {isSubmitting ? 'Logging in...' : 'Login'}
      </button>
    </form>
  )
}

// Key points:
// 1. Always use e.preventDefault()
// 2. Disable button during submission
// 3. Show loading state
// 4. Handle errors
// 5. Clear form after success

Interactive Demo

ReactPlayground.jsx
Code Editor
Preview

💡 Tip: Edit the code above and click "Run" to see your changes

Common Form Patterns

Clearing Form After Submit

pattern-clear.jsx
function Form() {
  const initialState = { name: '', email: '' }
  const [formData, setFormData] = React.useState(initialState)
  
  const handleSubmit = (e) => {
    e.preventDefault()
    console.log(formData)
    
    // Clear form
    setFormData(initialState)
  }
}

Disabling Submit When Invalid

pattern-disable.jsx
function Form() {
  const [email, setEmail] = React.useState('')
  const [password, setPassword] = React.useState('')
  
  const isValid = email.length > 0 && password.length >= 8
  
  return (
    <form onSubmit={handleSubmit}>
      <input value={email} onChange={e => setEmail(e.target.value)} />
      <input value={password} onChange={e => setPassword(e.target.value)} />
      <button type="submit" disabled={!isValid}>
        Submit
      </button>
    </form>
  )
}

Trimming Input on Blur

pattern-trim.jsx
function Form() {
  const [name, setName] = React.useState('')
  
  const handleBlur = () => {
    setName(name.trim())  // Remove whitespace when user leaves input
  }
  
  return (
    <input
      value={name}
      onChange={(e) => setName(e.target.value)}
      onBlur={handleBlur}
    />
  )
}

Key Takeaways

  • Use controlled components - state controls input values
  • Set value prop and onChange handler on inputs
  • Use checked prop for checkboxes/radios, not value
  • Always call event.preventDefault() in onSubmit
  • Store form data in single state object for multiple inputs
  • Use generic handler with name attributes
  • Check type to handle checkboxes vs text inputs
  • Disable submit button during submission
  • Show loading state during async operations
  • Clear form after successful submission
  • Textarea uses value prop in React (not children)
  • Select uses value on the select element
  • Controlled components enable validation and transformation

What's Next?

You now know how to build forms in React! You can handle all types of inputs, manage form state efficiently, and submit forms properly.

But forms aren't complete without validation. In the next lesson, you'll learn about Form Validation:

  • Real-time validation patterns
  • Validation on blur vs on change
  • Displaying error messages
  • Custom validation rules
  • Form-level vs field-level validation

Get ready to build bulletproof forms with proper validation! ✅

Learning how to build controlled forms in React!

Previous
Event Objects
Next
Form Validation

Never Miss a New React Tutorial

Join 2,000+ developers learning React step-by-step. Get new tutorials, tips, and exclusive resources delivered to your inbox - completely FREE.

You might also like

UI Components

Ready-made components for your projects

Developer Tools

Boost productivity with handy generators

HTML Game

Learn HTML concepts through interactive gameplay

Join Our Web Development Training Program

Master frontend & backend development with hands-on projects.

React Tutorials

0 of 42 completed

Your Progress0%

Topics

Getting Started

  • What is React?
  • React vs Vanilla JavaScript
  • Setting Up Your Environment
  • Your First React App

JSX Fundamentals

  • Introduction to JSX
  • JSX Expressions and Variables
  • Conditional Rendering
  • Lists and Keys
  • Styling in JSX

Components Basics

  • Function Components
  • Props
  • Children Prop
  • Props Destructuring
  • Component Composition

State Management

  • Introduction to State
  • useState Hook
  • State Updates and Re-renders
  • Multiple State Variables
  • State Best Practices

Events and Interactivity

  • Handling Events
  • Event Objects
  • Forms in React
  • Form Validation

Side Effects and Data

  • Introduction to useEffect
  • Data Fetching
  • Cleanup Functions
  • Dependency Arrays

Advanced Hooks

  • useRef Hook
  • useContext Hook
  • useMemo Hook
  • useCallback Hook

React Patterns

  • Custom Hooks
  • Higher-Order Components
  • Render Props Pattern

React Router

  • Introduction to React Router
  • Routes and Navigation
  • Dynamic Routes and Parameters

Best Practices

  • Component Organization
  • Performance Optimization
  • Error Handling
  • Testing React Components

Real World Project

  • Building a Complete App
Falytom logoFALYTOM

Learn technologies like HTML, CSS, JavaScript, React, NodeJS and more through interactive games, tutorials, components and free tools. Transform your businesses with AI chatbots, SEO-optimized websites, and professional development services.

© 2025 Tomilola Group
  • Facebook logo
  • Twitter logo
  • Instagram logo
  • LinkedIn logo
  • GitHub logo
  • YouTube logo