Skip to main content
New to FormEngine? It’s a React library that renders forms from JSON schemas. This guide shows how to troubleshoot when something isn’t working as expected. Start here →

What you’ll learn

  • How to inspect current form data and validation state
  • How to trace validation errors to specific fields
  • How to diagnose JSON schema problems (missing components, wrong type names)
  • How to debug conditional logic, actions, and events
  • A step-by-step diagnostic checklist for “my form doesn’t work” scenarios

Inspect current form data

The most common debugging task is checking: “What data does my form actually have right now?” Use the onFormDataChange callback to log form state every time it changes:
import { FormViewer } from '@react-form-builder/core';
import { useRef, useState } from 'react';

export default function MyForm() {
  const viewerRef = useRef(null);
  const [debugData, setDebugData] = useState(null);

  const schema = JSON.stringify({
    key: 'myForm',
    type: 'Screen',
    children: [
      { key: 'userName', type: 'RsInput', props: { label: 'Username' } },
      { key: 'email', type: 'RsInput', props: { label: 'Email' } },
    ],
  });

  const handleFormDataChange = (data, errors) => {
    console.log('📊 Form data:', data);
    console.log('❌ Validation errors:', errors);
    setDebugData({ data, errors });
  };

  return (
    <>
      <FormViewer
        ref={viewerRef}
        view={view}
        form={schema}
        initialData={{ userName: 'john_doe' }}
        onFormDataChange={handleFormDataChange}
      />
      
      {/* Debug panel */}
      {debugData && (
        <div style={{ marginTop: '20px', padding: '12px', backgroundColor: '#f5f5f5', borderRadius: '4px', fontFamily: 'monospace', fontSize: '12px' }}>
          <strong>Current form state:</strong>
          <pre>{JSON.stringify(debugData, null, 2)}</pre>
        </div>
      )}
    </>
  );
}
What to look for:
  • data object: does it contain all your fields with the correct keys?
  • errors object: which fields have validation errors? Are they the fields you expect?
  • Are keys spelled correctly (case-sensitive)? A field with key: "userName" will show as userName in data, not username.

Trace validation errors

When a form doesn’t submit and you see “validation failed” but can’t find which field is wrong, use getValidationResult():
import { FormViewer } from '@react-form-builder/core';
import { useRef } from 'react';

export default function MyForm() {
  const viewerRef = useRef(null);

  const schema = JSON.stringify({
    key: 'myForm',
    type: 'Screen',
    children: [
      { 
        key: 'email', 
        type: 'RsInput', 
        props: { label: 'Email' },
        validations: [{ type: 'email', errorType: 'error' }]
      },
      { 
        key: 'age', 
        type: 'RsInput', 
        props: { label: 'Age' },
        validations: [{ type: 'min', value: 18, errorType: 'error' }]
      },
    ],
  });

  const handleSubmit = async () => {
    // Get the form instance
    const form = viewerRef.current?.getForm();
    
    // Check validation result
    const validationResult = form?.getValidationResult();
    console.log('🔍 Full validation result:', validationResult);
    
    if (validationResult?.isValid) {
      console.log('✅ Form is valid, submitting...');
      const data = form?.getData();
      console.log('📤 Submitting data:', data);
    } else {
      console.log('❌ Form has errors:', validationResult?.errors);
      // Print each error clearly
      Object.entries(validationResult?.errors || {}).forEach(([key, error]) => {
        console.error(`Field "${key}": ${error}`);
      });
    }
  };

  return (
    <>
      <FormViewer
        ref={viewerRef}
        view={view}
        form={schema}
      />
      <button onClick={handleSubmit} style={{ marginTop: '12px' }}>
        Submit & Debug
      </button>
    </>
  );
}
Common issue: “I see the form but validation doesn’t show errors until I click submit.” Reason: By default, FormEngine only shows errors on touched fields (user has interacted with them). Before submission, fields are untouched → no error display. Solution: Call getValidationResult() to see ALL errors regardless of touch state.

Debug JSON schema issues

If a form doesn’t render or some fields disappear, the problem is usually in your JSON schema.

Component type not found

The most common issue: wrong component type name. FormEngine doesn’t throw an error when a type doesn’t exist — it silently skips the component. Check your browser console for warnings:
[FormEngine] Unknown component type "TextField" 
(did you mean "RsInput" from RSuite package?)
Type names vary by package:
PackageText inputDropdownCheckboxWizard
RSuiteRsInputRsDropdownRsCheckboxRsWizard
Material UIMuiTextFieldMuiSelectMuiCheckbox
MantineMtTextInputMtSelectMtCheckbox
Debug checklist:
  1. Open your browser DevTools Console (F12 → Console tab)
  2. Look for [FormEngine] warnings
  3. Cross-check your type values against the package you installed
  4. Common typos:
    • RsInput not RsTextInput or RsTextField
    • RsDropdown not RsSelect or RsSelectPicker
    • MuiTextField not MuiInput or TextField
Example fix:
// ❌ Wrong — type doesn't exist
{ key: 'name', type: 'TextField', props: { label: 'Name' } }

// ✅ Right — correct RSuite type
{ key: 'name', type: 'RsInput', props: { label: 'Name' } }

// ✅ Right — correct Mantine type
{ key: 'name', type: 'MtTextInput', props: { label: 'Name' } }

Verify keys match your data

A common source of confusion: keys must match exactly, and they’re case-sensitive.
const schema = JSON.stringify({
  key: 'myForm',
  type: 'Screen',
  children: [
    { key: 'userName', type: 'RsInput', props: { label: 'Username' } },  // Key: userName (camelCase)
    { key: 'email_address', type: 'RsInput', props: { label: 'Email' } }, // Key: email_address (snake_case)
  ],
});

// Later, when reading form data:
const form = viewerRef.current?.getForm();
const data = form?.getData();

console.log(data.userName);       // ✅ Works — matches schema key exactly
console.log(data.username);       // ❌ Undefined — wrong case
console.log(data.email_address);  // ✅ Works — exact match
console.log(data.emailAddress);   // ❌ Undefined — wrong case
Debug checklist:
  • Print your schema to console and verify all key values
  • Print your form data and check that keys match exactly
  • Compare key casing character-by-character

Debug actions and events

If a button click doesn’t trigger your function, the problem is usually in the action definition or event binding.
import { ActionDefinition } from '@react-form-builder/core';

// Define your action
const myCustomAction = new ActionDefinition({
  name: 'myCustomAction',
  functionalAction: (payload) => {
    console.log('🎯 Action triggered!');
    console.log('Payload:', payload);
    // Your logic here
    return { success: true };
  },
});

// Add to your form schema
const schema = JSON.stringify({
  key: 'myForm',
  type: 'Screen',
  children: [
    {
      key: 'submitBtn',
      type: 'RsButton',
      props: { text: 'Submit' },
      events: [
        {
          eventName: 'onClick',
          actionName: 'myCustomAction',  // Must match action.name exactly
        },
      ],
    },
  ],
});

// Render with action registered
<FormViewer
  ref={viewerRef}
  view={view}
  form={schema}
  actions={[myCustomAction]}  // Pass actions array
/>
Common issues:
  • actionName doesn’t match the action’s name → action never runs
  • Action not included in the actions array passed to <FormViewer /> → action not found
  • Action function throws an error → check browser console for stack trace
Debug tip: Add console.log at the top of your functionalAction function to confirm it’s being called.

Debug conditional logic

Conditional rendering (renderWhen) can silently fail if field keys or expressions are wrong.
const schema = JSON.stringify({
  key: 'myForm',
  type: 'Screen',
  children: [
    { key: 'userType', type: 'RsDropdown', props: { 
      label: 'User Type',
      data: [
        { label: 'Individual', value: 'individual' },
        { label: 'Company', value: 'company' },
      ],
    }},
    {
      key: 'companyName',
      type: 'RsInput',
      props: { label: 'Company Name' },
      renderWhen: [
        {
          fieldKey: 'userType',  // Must match the key exactly above
          expression: 'userType === "company"',  // Expression syntax
        },
      ],
    },
  ],
});
Debug checklist:
  • Print your schema and verify fieldKey matches a field’s key exactly (case-sensitive)
  • Test the expression in browser console:
    const data = { userType: 'company' };
    const fieldKey = 'userType';
    const result = eval(expression);  // Test: userType === "company" → true
    console.log(result);
    
  • Check that the field you’re referencing has rendered before (appears earlier in children array)
Common issue: “I set renderWhen but the field is always hidden.” Reason: Expression evaluates to false. Check:
  1. Is the referenced field’s value what you expect?
  2. Is the operator correct? (=== for strings, not ==)
  3. Is the quoted value correct? ("company" not company)

Performance debugging

If your form is slow or re-renders too much, use React DevTools Profiler:
  1. Open React DevTools (Chrome Extension)
  2. Go to Profiler tab
  3. Click Record, interact with your form, click Stop
  4. Look for excessive re-renders of <FormViewer /> component
Common cause: onFormDataChange callback is defined inline, causing re-render on every keystroke. Fix — use useCallback:
import { useCallback } from 'react';

export default function MyForm() {
  const handleFormDataChange = useCallback((data, errors) => {
    console.log('Form changed:', data);
    // This function reference is stable now
  }, []);

  return (
    <FormViewer
      ref={viewerRef}
      view={view}
      form={schema}
      onFormDataChange={handleFormDataChange}  // Stable reference
    />
  );
}

Diagnostic flowchart: “My form doesn’t work”

Follow this checklist step-by-step:

Form doesn’t render at all

  • ✅ Check: Is <FormViewer /> component imported and mounted?
  • ✅ Check: Is form prop a valid JSON string? Try: const form = JSON.stringify({...})
  • ✅ Check: Does your schema have a root object with type: 'Form'?
  • ✅ Check: Is view prop passed? Example: view={view} from your UI library
  • Debug: console.log(schema) to see raw JSON, paste in JSON validator

Fields don’t appear

  • ✅ Check: Does the schema have a children array?
  • ✅ Check: Are all type names correct? Open DevTools Console, look for [FormEngine] Unknown component type warnings
  • ✅ Check: Is the component installed? Example: did you npm install @react-form-builder/components-rsuite?
  • Debug: Log schema to console, cross-check type names against package docs

Form renders but data isn’t captured

  • ✅ Check: Does each field have a unique key?
  • ✅ Check: Is the key you’re reading the same case as the schema key?
  • ✅ Check: Is onFormDataChange callback defined? Add console.log to see if it fires
  • Debug: console.log(form.getData()) to see what data exists

Validation doesn’t work

  • ✅ Check: Is validations array present on the field?
  • ✅ Check: Is errorType set to "error" or "warning"?
  • ✅ Check: Are validation conditions correct? Example: min: 18 not min: "18" (number, not string)
  • ✅ Check: Has the field been touched? Call getValidationResult() to see all errors regardless
  • Debug: console.log(getValidationResult()) to see all validation errors

Button click doesn’t work

  • ✅ Check: Is the field type correct? Should be RsButton, MuiButton, or MtButton
  • ✅ Check: Does the field have an events array?
  • ✅ Check: Is eventName spelled correctly? Usually "onClick"
  • ✅ Check: Is actionName registered? Pass action to actions prop: <FormViewer actions={[myAction]} />
  • ✅ Check: Does action name match actionName in events?
  • Debug: Add console.log inside your action function to confirm it’s called

Form shows old data

  • ✅ Check: Did you update initialData prop?
  • ✅ Check: Did you pass key prop to <FormViewer /> to force re-mount? Example: key={resetCounter}
  • Debug: console.log('Rendering with initial data:', initialData)

Common mistakes

MistakeSymptomFix
Field type doesn’t existNo error, field silently missingCheck DevTools Console, correct type name
Key mismatch (case)data.userName is undefinedUse exact case: userName not username
Action not registeredButton clicked, nothing happensPass action to actions prop
Action name typoButton doesn’t triggerEnsure actionName === action’s name
Missing children arrayForm renders but no fieldsAdd children: [...] to schema
Wrong validation type”min 18” doesn’t work on age fieldUse correct validation: { type: 'min', value: 18 }
Field always hiddenrenderWhen field never appearsCheck expression is truthy, field key matches
Form data undefinedgetData() returns undefinedCall after fields render, check getForm() returns form instance

Next steps

Validation & Error Handling

Deep dive into validation rules, custom validators, and error messages.

Conditional Fields & Logic

Master renderWhen, conditional validation, and dynamic form logic.

Form Submission & Actions

Handle form submission, server errors, and custom actions.

Form Data Handling

Handle form data, initial values, and form state management.
Last modified on April 16, 2026