Dynamic Form Builder in React with TypeScript
Building a dynamic form builder is a common requirement in many applications, allowing users to create and customize forms based on their needs. This challenge asks you to create a React component that can render a form based on a JSON configuration, enabling flexibility and reusability in form creation. This is useful for applications where form structures are not fixed and need to be adaptable.
Problem Description
You are tasked with creating a DynamicFormBuilder component in React using TypeScript. This component will accept a JSON configuration object as a prop and render a corresponding form. The configuration object will define the fields to be included in the form, their types, labels, and any validation rules.
Key Requirements:
- Dynamic Rendering: The component must dynamically render form elements based on the provided JSON configuration.
- Supported Field Types: The component should support at least the following field types:
text,number,email,textarea,select, andcheckbox. Forselect, the configuration should include an array ofoptionswithvalueandlabelproperties. Forcheckbox, the configuration should include adefaultValueproperty. - Labels: Each field should be rendered with a corresponding label.
- Input Handling: The component should manage the state of each input field and provide a function to retrieve the form data as a JavaScript object.
- Validation (Basic): Implement basic validation based on the
typeof the field.emailfields should be validated for a valid email format.numberfields should be validated to ensure they are numbers.textfields should not be empty. - Error Handling: Display error messages next to invalid fields.
Expected Behavior:
- When the
configurationprop changes, the form should re-render to reflect the new configuration. - Input values should be stored in the component's state.
- The
onSubmitprop (a function) should be called when the form is submitted, passing the form data as an argument. - The form should visually represent the structure defined in the configuration.
Edge Cases to Consider:
- Empty configuration object.
- Invalid field types in the configuration.
- Missing labels or options for select fields.
- Configuration errors (e.g., incorrect data types).
- Handling of disabled fields (add a
disabledproperty to the configuration).
Examples
Example 1:
Input:
configuration = [
{
"type": "text",
"label": "Name",
"name": "name"
},
{
"type": "email",
"label": "Email",
"name": "email"
},
{
"type": "select",
"label": "Country",
"name": "country",
"options": [
{ "value": "US", "label": "United States" },
{ "value": "CA", "label": "Canada" },
{ "value": "UK", "label": "United Kingdom" }
]
}
]
Output: A form with three fields: a text input for "Name", an email input for "Email", and a select dropdown for "Country" with the specified options.
Explanation: The component renders the form elements based on the provided configuration. Each field has a label and a corresponding input element.
Example 2:
Input:
configuration = [
{
"type": "number",
"label": "Age",
"name": "age"
},
{
"type": "checkbox",
"label": "Agree to Terms",
"name": "terms",
"defaultValue": true
}
]
Output: A form with a number input for "Age" and a checkbox for "Agree to Terms" that is initially checked.
Explanation: The component renders a number input and a checkbox based on the configuration. The checkbox is initially checked because of the defaultValue property.
Example 3: (Edge Case)
Input:
configuration = []
Output: An empty form (no fields rendered).
Explanation: The component handles the case where the configuration is empty by not rendering any form elements.
Constraints
- Time Limit: You have 2 hours to complete this challenge.
- Dependencies: You can use standard React and TypeScript libraries. No external UI libraries (like Material UI or Ant Design) are allowed.
- Code Quality: Your code should be well-structured, readable, and maintainable. Use appropriate TypeScript types and comments.
- Performance: The component should render efficiently, even with a large number of fields in the configuration. Avoid unnecessary re-renders.
- Configuration Size: The configuration object can contain up to 20 fields.
Notes
- Consider using a state management library (like useState) to manage the form data.
- Think about how to handle different field types and their corresponding input elements.
- Focus on creating a flexible and reusable component that can handle various form configurations.
- The validation should be basic and focus on the most common validation rules for each field type. More complex validation can be added as an extension.
- Consider using a mapping of field types to React components to simplify the rendering process.
- The
onSubmitfunction should be called only when the form is valid.