Forms & User Input

The search bar in my POS system is the most critical feature. Restaurant staff need to find "Shan Noodles" among 200+ menu items instantly. Retail clerks search product codes while customers wait. A slow or buggy search interface directly impacts sales.

Building forms in React initially confused me. HTML forms have built-in stateβ€”the DOM tracks input values. But React wants to control that state. This is the concept of "controlled components," and once you understand it, forms become straightforward.

The Problem: Uncontrolled vs Controlled

Uncontrolled (Traditional HTML):

function SearchBar() {
  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const formData = new FormData(e.currentTarget);
    const searchTerm = formData.get('search');
    console.log('Searching for:', searchTerm);
  };
  
  return (
    <form onSubmit={handleSubmit}>
      <input type="text" name="search" placeholder="Search products..." />
      <button type="submit">Search</button>
    </form>
  );
}

This works, but React doesn't know the input value until form submission. You can't:

  • Show live search results as user types

  • Validate input in real-time

  • Clear the input programmatically

  • Disable submit based on input

Controlled (React Way):

Now React controls the input:

  • value={searchTerm} sets the input value from state

  • onChange updates state when user types

  • State is the single source of truth

  • We can access searchTerm anywhere, anytime

Live Search: Real-Time Filtering

In the POS, search results appear instantly as users type. No submit button needed:

Every keystroke:

  1. User types β†’ onChange fires

  2. setSearchTerm updates state

  3. Component re-renders

  4. filteredProducts recalculates

  5. UI updates instantly

Multiple Form Fields

Real forms have multiple inputs. Here's an "Add Product" form from the POS admin:

Key pattern:

  • Single formData object holds all field values

  • Single handleChange function updates any field

  • Use name attribute to identify which field changed

  • [name]: value uses computed property names

Form Validation

In production, validate before submission. Here's the POS product form with validation:

Validation strategy:

  • errors: Stores error messages for each field

  • touched: Tracks which fields user interacted with

  • onBlur: Mark field as touched when user leaves it

  • Show errors only if: Field has error AND user touched it

  • Clear errors: When user starts typing again

  • Validate on submit: Mark all fields touched, then validate

Checkboxes and Radio Buttons

These work slightly differently. From the POS admin settings:

Key differences:

  • Checkboxes: Use checked prop and e.target.checked

  • Radio buttons: Use checked={value === state} pattern

  • Both need onChange to be controlled

Textarea

Textareas work like text inputs:

Advanced: Search with Debouncing

In production, I debounced the search to avoid filtering on every keystroke. Here's a simpler pattern without external libraries:

We'll cover useEffect in detail in the next article. For now, understand it delays the filter operation.

Complete Example: Product Search & Filter Form

Combining everythingβ€”search, filters, sorting:

Key Learnings

βœ… Controlled Components Pattern

βœ… Single Source of Truth

  • State controls the input

  • Input updates state

  • Never let DOM and state diverge

βœ… Form Submission

βœ… Validation Strategy

  • Track errors in state

  • Track touched fields

  • Show errors only if touched

  • Clear errors on typing

βœ… Input Types

  • Text/Number/Select: value + onChange

  • Checkbox: checked + onChange (use e.target.checked)

  • Radio: checked={value === state} pattern

Common Mistakes I Made

❌ Forgetting e.preventDefault()

❌ Uncontrolled input (no value prop)

❌ Using value for checkboxes

❌ Showing errors immediately

Next Steps

Forms collect data, but where does it come from? In the POS system, product data comes from the Inventory Service API. I needed to fetch data when components mount, handle loading states, and manage errors.

Next, we'll learn useEffect for side effects like API calls, building a product catalog that loads data from a backend.

Continue to: Effects & Data Fetching

Last updated