Skip to main content
New to FormEngine? It’s a React library that renders forms from JSON schemas — free, MIT-licensed. Start here →

What You’ll Learn

In this tutorial, you’ll learn how to reset FormEngine forms by:
  • Clearing all form fields
  • Restoring forms to their initial values
  • Resetting a form after successful submission
  • Using key-based remounting to force a reset
  • Programmatically resetting via viewerRef
  • Handling edge cases and common mistakes
Resetting forms is essential for multi-step workflows, clearing data after submission, and improving UX by giving users a way to start fresh.

The Simplest Approach: Key-Based Remounting

The most reliable way to reset a FormEngine form is to force React to remount the FormViewer component by changing its key prop. When a component’s key changes, React creates a new instance, and initialData is applied fresh.
import React, { useState } from 'react';
import { FormViewer } from '@react-form-builder/core';
import { view } from '@react-form-builder/components-rsuite';

const form = {
  key: 'contactForm',
  type: 'Screen',
  children: [
    {
      key: 'name',
      type: 'RsInput',
      props: {
        label: 'Your Name',
        placeholder: 'Enter your name'
      }
    },
    {
      key: 'email',
      type: 'RsInput',
      props: {
        label: 'Your Email',
        placeholder: 'Enter your email'
      }
    },
    {
      key: 'message',
      type: 'RsTextArea',
      props: {
        label: 'Message',
        placeholder: 'Write your message here'
      }
    },
    {
      key: 'submitBtn',
      type: 'RsButton',
      props: {
        label: 'Send Message'
      }
    }
  ]
};

export default function ContactForm() {
  // Use a key to track form remounts
  const [formKey, setFormKey] = useState(0);

  const handleReset = () => {
    // Incrementing the key forces React to remount the FormViewer
    setFormKey(prevKey => prevKey + 1);
  };

  return (
    <div>
      <FormViewer
        key={formKey}
        view={view}
        getForm={async () => form}
      />
      <button onClick={handleReset} style={{ marginTop: '10px' }}>
        Clear Form
      </button>
    </div>
  );
}
When the user clicks Clear Form, the key changes, React unmounts and remounts the FormViewer, and all fields return to empty. Why this works: React treats components with different key values as completely different instances. Remounting reinitializes all internal state, and initialData is applied fresh.

Reset to Initial Values

If your form has default values via initialData, remounting will restore those values:
import React, { useState } from 'react';
import { FormViewer } from '@react-form-builder/core';
import { view } from '@react-form-builder/components-rsuite';

const form = {
  key: 'editForm',
  type: 'Screen',
  children: [
    {
      key: 'firstName',
      type: 'RsInput',
      props: { label: 'First Name' }
    },
    {
      key: 'lastName',
      type: 'RsInput',
      props: { label: 'Last Name' }
    },
    {
      key: 'role',
      type: 'RsDropdown',
      props: {
        label: 'Role',
        data: [
          { label: 'Admin', value: 'admin' },
          { label: 'User', value: 'user' }
        ]
      }
    },
    {
      key: 'saveBtn',
      type: 'RsButton',
      props: { label: 'Save Changes' }
    }
  ]
};

export default function EditForm() {
  const [formKey, setFormKey] = useState(0);

  // These are the original/default values
  const defaultValues = {
    firstName: 'John',
    lastName: 'Doe',
    role: 'user'
  };

  const handleReset = () => {
    // Reset back to the original values
    setFormKey(prevKey => prevKey + 1);
  };

  return (
    <div>
      <FormViewer
        key={formKey}
        view={view}
        getForm={async () => form}
        initialData={defaultValues}
      />
      <button onClick={handleReset} style={{ marginTop: '10px' }}>
        Restore Original Values
      </button>
    </div>
  );
}
Now when the user edits the form and clicks Restore Original Values, the form remounts with the original defaultValues.

Reset After Successful Submission

A common UX pattern is to clear the form after the user successfully submits it:
import React, { useState, useRef } from 'react';
import { FormViewer } from '@react-form-builder/core';
import { view } from '@react-form-builder/components-rsuite';

const form = {
  key: 'surveyForm',
  type: 'Screen',
  children: [
    {
      key: 'q1',
      type: 'RsInput',
      props: { label: 'What is your name?' }
    },
    {
      key: 'q2',
      type: 'RsInput',
      props: { label: 'What is your feedback?' }
    },
    {
      key: 'submitBtn',
      type: 'RsButton',
      props: {
        label: 'Submit Survey'
      },
      events: {
        onClick: async (e) => {
          // e.data contains the current form data
          const formData = e.data;
          
          try {
            // Send to API
            const response = await fetch('/api/survey', {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify(formData)
            });

            if (response.ok) {
              alert('Survey submitted successfully!');
              // Reset the form after successful submission
              e.form.reset?.();
            } else {
              alert('Submission failed. Please try again.');
            }
          } catch (error) {
            alert('Error: ' + error.message);
          }
        }
      }
    }
  ]
};

export default function SurveyForm() {
  const [formKey, setFormKey] = useState(0);
  const formRef = useRef(null);

  // Alternative: if e.form.reset() is not available,
  // you can trigger the remount from the parent
  const resetForm = () => {
    setFormKey(prevKey => prevKey + 1);
  };

  return (
    <FormViewer
      key={formKey}
      view={view}
      getForm={async () => form}
      viewerRef={formRef}
    />
  );
}
In this pattern, the form’s submit button has an onClick action that sends data to the API. If the submission succeeds, the form resets. You can either call e.form.reset?.() (if available in your version) or manage the reset from the parent component.

Clear Form to Empty (No Defaults)

If you don’t need to restore to initial values and just want to clear the form completely, remounting without initialData does the trick:
import React, { useState } from 'react';
import { FormViewer } from '@react-form-builder/core';
import { view } from '@react-form-builder/components-rsuite';

const form = {
  key: 'quickForm',
  type: 'Screen',
  children: [
    {
      key: 'input1',
      type: 'RsInput',
      props: { label: 'Field 1' }
    },
    {
      key: 'input2',
      type: 'RsInput',
      props: { label: 'Field 2' }
    },
    {
      key: 'clearBtn',
      type: 'RsButton',
      props: { label: 'Clear All' }
    }
  ]
};

export default function QuickForm() {
  const [formKey, setFormKey] = useState(0);

  const handleClear = () => {
    setFormKey(prevKey => prevKey + 1);
  };

  return (
    <div>
      <FormViewer
        key={formKey}
        view={view}
        getForm={async () => form}
        // No initialData — form starts empty
      />
      <button onClick={handleClear}>
        Clear Form
      </button>
    </div>
  );
}
All fields render empty, and the button clears them completely.

Programmatic Reset via viewerRef

If your version of FormEngine exposes methods on viewerRef.current, you can reset programmatically without remounting:
import React, { useRef } from 'react';
import { FormViewer } from '@react-form-builder/core';
import { view } from '@react-form-builder/components-rsuite';

const form = {
  key: 'demoForm',
  type: 'Screen',
  children: [
    {
      key: 'username',
      type: 'RsInput',
      props: { label: 'Username' }
    },
    {
      key: 'password',
      type: 'RsInput',
      props: { label: 'Password', type: 'password' }
    }
  ]
};

export default function LoginForm() {
  const formRef = useRef(null);

  const handleReset = () => {
    if (formRef.current && typeof formRef.current.reset === 'function') {
      // If reset method exists, use it
      formRef.current.reset();
    } else if (formRef.current) {
      // Alternative: manually clear form data
      formRef.current.formData = {
        username: '',
        password: ''
      };
    }
  };

  return (
    <div>
      <FormViewer
        view={view}
        getForm={async () => form}
        viewerRef={formRef}
      />
      <button onClick={handleReset}>
        Reset Form
      </button>
    </div>
  );
}
Note: The availability of reset() method depends on your FormEngine version. Check your documentation or the viewerRef.current object to see what methods are available. If not available, stick with the key-based remounting approach.

Combining Reset with Form Data Tracking

Track form changes while allowing reset. When you reset, the form state clears:
import React, { useState, useRef } from 'react';
import { FormViewer } from '@react-form-builder/core';
import { view } from '@react-form-builder/components-rsuite';

const form = {
  key: 'trackForm',
  type: 'Screen',
  children: [
    {
      key: 'name',
      type: 'RsInput',
      props: { label: 'Name' }
    },
    {
      key: 'email',
      type: 'RsInput',
      props: { label: 'Email' }
    }
  ]
};

export default function TrackAndResetForm() {
  const [formKey, setFormKey] = useState(0);
  const [currentData, setCurrentData] = useState({});
  const formRef = useRef(null);

  const handleFormDataChange = ({ data, errors }) => {
    setCurrentData(data);
  };

  const handleReset = () => {
    setCurrentData({});
    setFormKey(prevKey => prevKey + 1);
  };

  return (
    <div>
      <FormViewer
        key={formKey}
        view={view}
        getForm={async () => form}
        onFormDataChange={handleFormDataChange}
        viewerRef={formRef}
      />
      <div style={{ marginTop: '10px' }}>
        <p>Current data: {JSON.stringify(currentData)}</p>
        <button onClick={handleReset}>Clear Form</button>
      </div>
    </div>
  );
}
Now you can monitor form changes in real-time and reset both the form state and your tracking state together.

Common Mistakes

1. Forgetting to Change the Key

If you try to reset without changing the key, nothing happens because React sees the same component and doesn’t remount:
// ❌ Wrong — key never changes
const handleReset = () => {
  // Do something, but don't change key
  console.log('Reset');
};

return <FormViewer key={0} ... />; // Key is always 0

// ✅ Correct
const [formKey, setFormKey] = useState(0);

const handleReset = () => {
  setFormKey(prevKey => prevKey + 1);
};

return <FormViewer key={formKey} ... />;

2. Assuming viewerRef.current Has a reset() Method

Different versions of FormEngine expose different APIs. Don’t assume reset() exists without checking:
// ❌ May fail if reset() doesn't exist
formRef.current.reset();

// ✅ Check first
if (formRef.current && typeof formRef.current.reset === 'function') {
  formRef.current.reset();
} else {
  // Fallback to key-based approach
  setFormKey(prevKey => prevKey + 1);
}

3. Stale Closure in Event Handlers

If you’re resetting inside an event handler, make sure you’re using the latest state:
// ❌ Stale closure — formKey never changes inside the handler
const handleReset = () => {
  const newKey = formKey + 1; // Captures old formKey
  setFormKey(newKey);
};

// ✅ Use setState with callback
const handleReset = () => {
  setFormKey(prevKey => prevKey + 1); // Correct
};

4. Resetting Too Frequently

Remounting the form every render or too frequently can cause performance issues and loss of focus states. Reset only when explicitly requested by the user:
// ❌ Too aggressive — resets on every prop change
useEffect(() => {
  setFormKey(prevKey => prevKey + 1);
}, [someProp]); // Remounts form constantly

// ✅ Reset only on user action
const handleReset = () => {
  setFormKey(prevKey => prevKey + 1);
};

5. Not Clearing Associated State

If you’re tracking form data separately (e.g., in parent state), reset that too:
// ❌ Form resets but parent state doesn't
const handleReset = () => {
  setFormKey(prevKey => prevKey + 1);
  // currentData state is NOT cleared
};

// ✅ Reset both
const handleReset = () => {
  setCurrentData({});
  setFormKey(prevKey => prevKey + 1);
};

When to Use Each Approach

ScenarioApproachWhy
Clear form, restore emptyKey-based remountSimple, reliable, no API assumptions
Restore to initial/default valuesKey-based remount with initialDataWorks with any form, any version
Clear after successful submitKey-based remount in submit handlerGuarantees clean state for next submission
Performance-critical (avoid remount)viewerRef.current.reset() or manual data clearIf available, avoids full remount overhead
Track changes while resettingKey + state managementAllows both monitoring and clearing

Next Steps

Now that you can reset forms, explore these related topics:
Last modified on April 16, 2026