Use a custom react library to render a headless form
You can create and implement custom components to customize the appearance and functionality (Behaviour) of your Headless adaptive forms as per requirement and guidelines of your organization.
These components serve two primary purposes: to control the appearance or style of form fields, and to store the data collected through these fields within the form model instance. If this sounds confusing, don’t worry - we will explore these purposes in greater detail shortly. For now, let’s focus on the initial steps of creating custom components, rendering the form using these components, and utilizing events to save and submit data to a REST endpoint.
In this tutorial, Google Material UI components are employed to demonstrate how to render a Headless adaptive form using custom React components. However, you are not limited to this library and are free to utilize any React components library or develop your own custom components.
By the conclusion of this article, the Contact Us form created in Create and publish a headless form using starter kit article transforms into the following:
The major steps involved in using Google Material UI components to render a form are:
1. Install Google Material UI
By default, the starter kit uses Adobe’s Spectrum components. Let’s set it to use Google’s Material UI:
-
Ensure that the starter kit is not running. To stop the starter kit, open your terminal, navigate to the react-starter-kit-aem-headless-forms, and press Ctrl-C (it’s the same on Windows, Mac & Linux).
Do not attempt to close the terminal. Closing your terminal does not stop the starter kit.
-
Run the following command:
npm install @mui/material @emotion/react @emotion/styled --force
It installs the Google Material UI npm libraries and adds the libraries to starter kits dependencies. You can now use Material UI components to render form components.
2. Create custom React components
Let’s create a custom component that replaces default text input component with Google Material UI Text Field component.
A separate component is required for each component type (fieldType or :type) used in a Headless Form definition. For example, in the Contact Us form that you created in the previous section, the Name, Email, and Phone fields of type text-input
(fieldType: “text-input”) and the message field is of type multiline-input
(“fieldType”: “multiline-input”).
Let’s create a custom component to overlay all form fields that use the fieldType: “text-input” property with Material UI Text Field component.
To create the custom component and map the custom component with the fieldType property :
-
Open the react-starter-kit-aem-headless-forms directory in a code editor and navigate to
\react-starter-kit-aem-headless-forms\src\components
. -
Create a copy of the slider or richtext folder, and rename the copied folder to materialtextfield. Slider and richtext are two sample custom components available in the starter app. You can use these to create your own custom components.
-
Open the
\react-starter-kit-aem-headless-forms\src\components\materialtextfield\index.tsx
file and replace the existing code with the below code. This code returns and renders a Google Material UI Text Field component.
import React from 'react';
import {useRuleEngine} from '@aemforms/af-react-renderer';
import {FieldJson, State} from '@aemforms/af-core';
import { TextField } from '@mui/material';
import Box from '@mui/material/Box';
import { richTextString } from '@aemforms/af-react-components';
import Typography from '@mui/material/Typography';
const MaterialtextField = function (props: State<FieldJson>) {
const [state, handlers] = useRuleEngine(props);
return(
<Box>
<Typography component="legend">{state.visible ? richTextString(state?.label?.value): ""} </Typography>
<TextField variant="filled"/>
</Box>
)
}
export default MaterialtextField;
The state.visible
part checks if the component is set to be visible. If it is, the label of the field is retrieved and displayed using richTextString(state?.label?.value)
.
Your custom component materialtextfield
is ready. Let’s set this custom component to replace all the instances of fieldType: “text-input” with Google Material UI Text Field.
3. Map custom component with headless form fields
The process of using a third-party library components to render form fields is know as mapping. You map each (fieldType) to corresponding component of third-party library.
All the mapping-related information is added to the mappings.ts
file. The ...mappings
statement in the mappings.ts
file refers to the default mappings, which overlays the (fieldType or :type) with Adobe Spectrum components.
To add mapping for the materialtextfield
component, created in last step:
-
Open the
mappings.ts
file. -
Add the following import statement to include the
materialtextfield
component to themappings.ts
file:code language-javascript import MaterialtextField from "../components/materialtextfield";
-
Add the following statement to map the
text-input
with the materialtextfield component.code language-javascript "text-input": MaterialtextField
The final code of the file looks like the following :
code language-javascript import { mappings } from "@aemforms/af-react-components"; import MaterialtextField from "../components/materialtextfield"; const customMappings: any = { ...mappings, "text-input": MaterialtextField }; export default customMappings;
-
Save and run the app. The first three fields of the form are rendered using Google Material UI Text Field:
Similarly you can create custom components for message (“fieldType”: “multiline-input”) and rate the service (“fieldType”:“number-input”) fields. You can clone the following Git repository for custom components of message and rate the service fields:
https://github.com/singhkh/react-starter-kit-aem-headless-forms
Next step
You have successfully rendered the form with custom components that use Google Material UI. Have you tried submitting the form by clicking the Submit Button (Mapped with corresponding Google Material UI component)? If not, go ahead and give it a try.
Is the form submitting the data to any data source? No? Don’t worry. This is because your form is not configured to communicate with runtime library.
How can you configure your form to communicate with it? We’ve got an article coming soon that will explain everything in detail. Stay tuned!