gform-react
Back to Guides

Dynamic Fields

Add and remove fields at runtime without losing the rest of the form's state.

gform-react registers each field by its formKey. That means you can add or remove GInputs at runtime - render them from a state array - and the rest of the form keeps its values. When a field unmounts, gform unregisters it; when it mounts, it registers fresh.

Pattern

Keep a list of stable ids in component state and map each to a GInput with a unique formKey.

DynamicOptions.tsx
import { useState } from "react";
import { GForm, GInput, GValidator, type GValidators } from "gform-react";
 
const validators: GValidators = {
  "*": new GValidator().withRequiredMessage("Required"),
};
 
let nextId = 1;
 
export default function DynamicOptions() {
  const [ids, setIds] = useState<number[]>([0]);
 
  return (
    <GForm
      validators={validators}
      onSubmit={(state, e) => {
        e.preventDefault();
        console.log(state.toRawData()); // { "option-0": …, "option-1": … }
      }}
    >
      {(state) => (
        <>
          {ids.map((id) => (
            <div key={id}>
              <GInput
                formKey={`option-${id}`}
                required
                element={(input, props) => (
                  <span>
                    <input {...props} placeholder={`Option ${id}`} />
                    {input.error && <small>{input.errorText}</small>}
                  </span>
                )}
              />
              <button type="button" onClick={() => setIds((xs) => xs.filter((x) => x !== id))}>
                Remove
              </button>
            </div>
          ))}
 
          <button type="button" onClick={() => setIds((xs) => [...xs, nextId++])}>
            Add option
          </button>
 
          <button disabled={state.isInvalid}>Submit</button>
        </>
      )}
    </GForm>
  );
}
Use a stable key

Give each row a stable id (not the array index) for both React's key and the formKey. That keeps values attached to the right field when you remove an item from the middle of the list.

Try it live

Loading playground…

Add a few options, fill them in, then remove one from the middle - the others keep their values.