Skip to content

Latest commit

 

History

History
179 lines (140 loc) · 4.47 KB

File metadata and controls

179 lines (140 loc) · 4.47 KB

Dynamic Form Fields

What Are Dynamic Form Fields?

Dynamic form fields are inputs that change based on user interaction or data — for example:

  • Adding or removing input fields on the fly.
  • Rendering fields conditionally based on a selection.
  • Populating form inputs from API data.
  • Handling arrays of form inputs (like multiple phone numbers, skills, or addresses).

Common Use Cases:

  • “Add More” buttons (e.g., adding more email addresses).
  • Conditional rendering (e.g., only show "Company Name" if "Employed" is selected).
  • Dynamic from API (form structure is fetched from backend and rendered).
  • Step-by-step forms where fields change per step.

Example 1 – Add/Remove Fields (useState)

import React, { useState } from 'react';

export default function DynamicFieldsExample() {
  const [fields, setFields] = useState(['']);

  const handleChange = (index: number, value: string) => {
    const updated = [...fields];
    updated[index] = value;
    setFields(updated);
  };

  const addField = () => setFields([...fields, '']);
  const removeField = (index: number) =>
    setFields(fields.filter((_, i) => i !== index));

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    console.log(fields);
  };

  return (
    <form onSubmit={handleSubmit}>
      {fields.map((value, index) => (
        <div key={index}>
          <input
            value={value}
            onChange={(e) => handleChange(index, e.target.value)}
            placeholder={`Field ${index + 1}`}
          />
          <button type="button" onClick={() => removeField(index)}>
            Remove
          </button>
        </div>
      ))}
      <button type="button" onClick={addField}>
        Add More
      </button>
      <button type="submit">Submit</button>
    </form>
  );
}

How it works:

  • State is an array of field values.
  • Adding/removing updates the array.
  • Rendering is based on .map().

Example 2 – Dynamic Fields with react-hook-form

React Hook Form has useFieldArray for this exact scenario.

import React from 'react';
import { useForm, useFieldArray } from 'react-hook-form';

type FormData = {
  emails: { value: string }[],
};

export default function RHFDynamicFields() {
  const { register, control, handleSubmit } =
    useForm <
    FormData >
    {
      defaultValues: { emails: [{ value: '' }] },
    };

  const { fields, append, remove } = useFieldArray({
    control,
    name: 'emails',
  });

  const onSubmit = (data: FormData) => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      {fields.map((field, index) => (
        <div key={field.id}>
          <input {...register(`emails.${index}.value`)} placeholder="Email" />
          <button type="button" onClick={() => remove(index)}>
            Remove
          </button>
        </div>
      ))}
      <button type="button" onClick={() => append({ value: '' })}>
        Add Email
      </button>
      <button type="submit">Submit</button>
    </form>
  );
}

Advantages:

  • Automatically handles field registration.
  • Maintains form state even after removing fields.
  • Works with validation (Zod, Yup).

Example 3 – Dynamic Fields from API

Sometimes the backend sends the form structure as JSON, and you loop through it to render fields.

import React, { useState, useEffect } from "react";

type Field = { name: string; type: string; label: string };

export default function APIDynamicForm() {
	const [fields, setFields] = useState<Field[]>([]);

	useEffect(() => {
		// Simulating API call
		setTimeout(() => {
			setFields([
				{ name: "name", type: "text", label: "Name" },
				{ name: "age", type: "number", label: "Age" },
			]);
		}, 500);
	}, []);

	const handleSubmit = (e: React.FormEvent) => {
		e.preventDefault();
		// Collect data manually or use form libraries
	};

	return (
		<form onSubmit={handleSubmit}>
			{fields.map((f) => (
				<div key={f.name}>
					<label>{f.label}</label>
					<input type={f.type} name={f.name} />
				</div>
			))}
			<button type="submit">Submit</button>
		</form>
	);
}

This is useful when your form structure is not fixed.


Key Points When Building Dynamic Forms

  • State shape matters → For multiple fields, store data as arrays/objects.
  • Unique keys → Use a stable id (like uuid) instead of array index if you expect reordering.
  • Validation → Works with Zod/Yup + useFieldArray.
  • Performance → Avoid unnecessary re-renders by splitting components.