Building Dynamic Forms in React with JSON Schema and Material-UI

In today’s rapidly evolving web development landscape, creating flexible and dynamic user interfaces is more important than ever. Imagine a scenario where you need to update your form fields and validations frequently based on changing business requirements. Traditionally, this would involve modifying your front-end code every time there’s a change. But what if you could fetch the form schema from a backend API and render it dynamically, without touching the UI code?

In this blog post, we’ll explore a React component that does exactly that. We’ll dive deep into a FormBuilder component built with React, Material-UI, and AJV (Another JSON Schema Validator). This component fetches the schema from a backend API, allowing you to add new fields and validations without changing your UI code.

Introduction

Building forms is a common task in web development, but maintaining and updating them can be cumbersome, especially when requirements change frequently. A schema-driven approach allows developers to define form structures and validations in a JSON schema, which can be fetched from a backend API. This decouples the form logic from the UI code, making it easier to maintain and extend.

The Need for Dynamic Forms

In traditional form handling:

  • Static Forms: Each form field is hard-coded in the UI, requiring code changes for any modification.
  • Maintenance Overhead: Adding or removing fields involves editing the UI code, increasing the risk of bugs.
  • Validation Logic: Validation is often duplicated on both the frontend and backend.

Dynamic forms address these issues by:

  • Flexibility: Forms adapt based on the schema received from the backend.
  • Reduced Code Changes: UI code remains untouched when form fields change.
  • Consistent Validation: Centralized validation logic using schemas.

Overview of the Solution

The FormBuilder component we’re exploring:

  • Fetches Schema: Retrieves the form schema from a backend API.
  • Dynamic Rendering: Uses the schema to render form fields dynamically.
  • AJV Integration: Validates form data against the schema using AJV.
  • Material-UI Components: Leverages Material-UI for consistent and modern UI elements.
  • Handles Dependencies: Manages field dependencies (e.g., dynamic dropdowns based on other fields).

Understanding the Code

Let’s break down the key parts of the code to understand how it achieves dynamic form rendering and validation.

Component Structure

The main component, FormBuilder, is structured as follows:

  • State Management:
    • formData: Holds the current values of the form fields.
    • errors: Stores validation errors.
    • dynamicSchema: The schema that may change based on field dependencies.
  • Effects:
    • Processing Initial Data: Uses processInitialData to set up initial form values.
    • Updating Schema: Adjusts the schema when field dependencies change.
  • Rendering:
    • FormGrid: A sub-component that lays out the form using Material-UI’s Grid.
    • renderInputField: A function that decides which input component to render based on the field type and ui:component specified in the schema.

Validation with AJV

AJV is a powerful JSON schema validator that ensures the form data adheres to the defined schema.

Setup:

  • Validation Function:
  • Error Handling: The getErrorForField function parses AJV’s error messages to display them next to the relevant form fields.

Rendering Fields Dynamically

The renderInputField function decides which form element to render based on the field’s type and ui:component.

  • String Fields:
    • Text input, rich text editor, date picker, time picker, select dropdowns, radio buttons.
  • Number Fields:
    • Numeric input, sliders.
  • Boolean Fields:
    • Checkboxes, switches.
  • Array Fields:
    • Multiple select, checkboxes, image uploader.
  • Object Fields:
    • Autocomplete components.

Example: Rendering a text field for a string type.

Handling Dependencies

Some form fields may depend on the values of others. For instance, the options in a dropdown may change based on another field’s selection.

Updating Schema Based on Dependencies:

  • Example Scenario: If you select a country in one field, the states/provinces dropdown updates to show only relevant options.

Advantages of Schema-Driven Forms

  • Backend Control: The backend defines the form structure, making it easier to implement role-based forms or A/B testing.
  • Consistency: Ensures that the frontend and backend validations are in sync.
  • Scalability: Adding new fields or modifying existing ones doesn’t require front-end code changes.
  • Maintainability: Reduces the codebase size and potential for bugs.

Conclusion

By leveraging JSON schemas, React, and Material-UI, we can create dynamic and flexible forms that adapt to changing requirements without modifying the UI code. The FormBuilder component exemplifies how powerful this approach can be, especially in applications where form structures are frequently updated.

Fetching the schema from a backend API not only decouples the frontend and backend but also streamlines the development process. With validation handled consistently across the stack, we ensure a better user experience and data integrity.

References

Tariq Siddiqui

Hi there! I'm Tariq Siddiqui, a Senior Software Engineer III with over 7 years of experience in web and mobile development. My passion and expertise lie in JavaScript, particularly in crafting dynamic and user-friendly applications using React and React Native.