Leverage Formik-Form-Builder Creator to effortlessly construct MUI-based forms using concise JSON definitions.
Play with it SANBOX
The provided code is a React component that uses Formik
for form management and a custom FormBuilder
component to dynamically generate form fields. Below is a detailed explanation of how to use this code, along with examples and usage scenarios.
Before using the code, ensure you have the necessary dependencies installed:
npm install formik-form-builder
yarn add formik-form-builder
- Formik: A popular library for building forms in React.
- Yup: A schema validation library often used with Formik.
- Material-UI (MUI): A UI library that provides pre-built components like text fields, checkboxes, etc.
The code imports several modules from formik
and a custom form-builder
module:
import { Form, Formik } from 'formik';
import { ConditionAction, ConditionName, FieldType, FormBuilder, InputTypes, PostCondition, useFormBuilder } from './form-builder';
-
Formik: Provides the
Formik
component andForm
helper. - FormBuilder: A custom component that dynamically generates form fields based on the provided configuration.
- useFormBuilder: A custom hook that initializes form values and validation schema.
The fields
array contains the configuration for each form field. Each field is an object with properties like field
, type
, label
, validation
, muiProps
, etc.
-
Text Input:
{ field: 'title', type: InputTypes.TEXT, label: 'Property Title', validation: { required: true, message: "First name is required" }, muiProps: { variant: 'soft', fullWidth: true } }
-
Checkbox:
{ field: 'MyCheckBox', type: InputTypes.CHECKBOX, groupLabel: "", helperText: "testing this checkbox with all the values", initialValue: [], validation: { required: true, message: "Please accept the terms", minLength: 1 }, muiProps: {}, options: [{ label: 'Option 1', value: 'option1', description: "test is not the only thing people of the memeber of the ithat is the best of the life of the need of" }], }
-
Radio Button:
{ field: 'radio1', type: InputTypes.RADIO, label: 'radio', groupLabel: 'Gender', initialValue: '', options: [{ label: 'Male', value: 'male' }, { label: 'Female', value: 'female' }], validation: { required: true, message: "Please accept the terms" } }
-
Select Dropdown:
{ field: 'select1', type: InputTypes.SELECT, label: 'Shazam', helperText: "They Please select the dog type", options: [{ label: 'Male', value: 'male' }, { label: 'Female', value: 'female' }, { label: 'select', value: '' }], validation: { required: true, message: "Please accept the terms" }, gridProps: { xs: 12, sm: 4 } }
The useFormBuilder
hook is used to generate initial values and validation schema based on the fields
array:
const { initailValues, yupSchemaValidation } = useFormBuilder(fields);
- initailValues: An object containing the initial values for each field.
-
yupSchemaValidation: A Yup validation schema generated based on the validation rules defined in the
fields
array.
The Formik
component is used to manage form state, validation, and submission:
<Formik
initialValues={initailValues}
validationSchema={yupSchemaValidation}
onSubmit={(values, actions) => {
setTimeout(() => {
console.log(values);
alert(JSON.stringify(values, null, 2));
actions.setSubmitting(false);
}, 1000);
}}
>
{({ values }) => (
<Form>
<FormBuilder group="form" fields={fields} data-test="form" values={values} />
<button type="submit">Submit</button>
</Form>
)}
</Formik>
- initialValues: The initial values for the form fields.
- validationSchema: The Yup validation schema.
- onSubmit: A callback function that is called when the form is submitted.
-
FormBuilder: A custom component that renders the form fields based on the
fields
array.
The conditions
property allows you to define conditional logic for showing/hiding fields based on the values of other fields:
conditions: {
action: ConditionAction.SHOW,
groups: [{
group: "check",
groupPostCondition: PostCondition.AND,
logic: [
{
field: 'test.firstName',
value: "10",
condition: ConditionName.EQUALS,
postCondition: PostCondition.AND
},
]
}]
}
-
action: Specifies whether to
SHOW
orHIDE
the field based on the condition. - groups: An array of condition groups.
- logic: An array of conditions that must be met for the action to take effect.
The gridProps
property allows you to define the layout of the form fields using Material-UI's grid system:
gridProps: { xs: 12, sm: 4 }
- xs: The number of columns the field should occupy on extra small screens.
- sm: The number of columns the field should occupy on small screens.
When the form is submitted, the onSubmit
function is called, which logs the form values and displays them in an alert:
onSubmit={(values, actions) => {
setTimeout(() => {
console.log(values);
alert(JSON.stringify(values, null, 2));
actions.setSubmitting(false);
}, 1000);
}}
Here is the complete example with all the fields and configurations:
import { Form, Formik } from 'formik';
import { ConditionAction, ConditionName, FieldType, FormBuilder, InputTypes, PostCondition, useFormBuilder } from './form-builder';
export function App() {
const fields: FieldType[] = [
{
field: 'title', type: InputTypes.TEXT, label: 'Property Title',
validation: { required: true, message: "First name is required" },
muiProps: { variant: 'soft', fullWidth: true }
},
{
field: 'test.lastName', type: InputTypes.TEXT, label: 'Last Name', initialValue: 'Doe',
helperText: "Enter your last Name",
validation: { required: true, message: "First name is required" },
muiProps: { variant: 'soft' },
conditions: {
action: ConditionAction.SHOW,
groups: [{
group: "check", groupPostCondition: PostCondition.AND, logic: [
{
field: 'test.firstName', value: "10", condition: ConditionName.EQUALS,
postCondition: PostCondition.AND
},
]
}]
}
},
{
field: 'test.amount', type: InputTypes.TEXT,
label: 'Amount', initialValue: 0,
helperText: "Enter your last Name",
validation: { required: true, message: "Amount is required", isPositive: true },
muiProps: { variant: 'soft', type: 'number' },
},
{
field: 'test.firstName', type: InputTypes.TEXT, label: 'Last 2', initialValue: 'sssss',
helperText: "Enter your last Name",
validation: { required: true, message: "First name is required" },
muiProps: { variant: 'soft' }
},
{
field: 'MyCheckBox', type: InputTypes.CHECKBOX, groupLabel: "",
helperText: "testing this checkbox with all the values",
initialValue: [],
validation: { required: true, message: "Please accept the terms", minLength: 1 },
muiProps: {},
options: [{ label: 'Option 1', value: 'option1', description: "test is not the only thing people of the memeber of the ithat is the best of the life of the need of" }],
},
{
field: 'MyCheckBox2', type: InputTypes.CHECKBOX, groupLabel: "Choose any one",
helperText: "testing this checkbox with all the values",
initialValue: [],
validation: { required: true, message: "Please accept the terms", minLength: 1 },
muiProps: {},
options: [{ label: 'Option 2', value: 'option2', description: "testing this option" }, { label: 'Option 6', value: 'option5', description: "what do you think I cant test this option " }],
},
{
field: 'radio1', type: InputTypes.RADIO, label: 'radio',
groupLabel: 'Gender',
initialValue: '',
options: [{ label: 'Male', value: 'male' }, { label: 'Female', value: 'female' }],
validation: { required: true, message: "Please accept the terms" }
},
{
field: 'radio2', type: InputTypes.RADIO, label: 'radio',
groupLabel: 'Gender',
initialValue: '',
options: [{ label: 'Male334', value: true }, { label: 'Female333', value: false }],
validation: { required: true, message: "Please accept the terms" }
},
{
field: 'select25', type: InputTypes.RADIO, label: 'Shazam 2', initialValue: '',
options: [{ label: 'Male', value: 'male' }, { label: 'Female', value: 'female' }],
validation: { required: true, message: "Please accept the terms" },
gridProps: { xs: 12, sm: 4 }
},
{
field: 'select30', type: InputTypes.AUTO_COMPLETE, label: 'Shazam 2', initialValue: '',
options: [{ label: 'Male', value: true }, { label: 'Female', value: false }],
validation: { required: true, message: "Please accept the terms" },
gridProps: { xs: 12, sm: 4 }
},
{
field: 'select1', type: InputTypes.SELECT, label: 'Shazam',
helperText: "They Please select the dog type",
options: [{ label: 'Male', value: 'male' }, { label: 'Female', value: 'female' }, { label: 'select', value: '' }],
validation: { required: true, message: "Please accept the terms" },
gridProps: { xs: 12, sm: 4 }
},
];
const { initailValues, yupSchemaValidation } = useFormBuilder(fields);
return (
<Formik
initialValues={initailValues}
validationSchema={yupSchemaValidation}
onSubmit={(values, actions) => {
setTimeout(() => {
console.log(values);
alert(JSON.stringify(values, null, 2));
actions.setSubmitting(false);
}, 1000);
}}
>
{({ values }) => (
<Form>
<FormBuilder group="form" fields={fields} data-test="form" values={values} />
<button type="submit">Submit</button>
</Form>
)}
</Formik>
);
}
export default App;
To run the application, simply include the App
component in your main index.js
or App.js
file and start the development server:
npm start
This will start the React application, and you should see the form rendered in your browser.
Author Created by codewithshinde.