In order to successfully render a form via FormRenderer you need to assign component mappers. Component mapper is an object of React components, where key is a component identifier and value is the component or an object with the component and globally defined props. Each component in mapper must have an unique key, which corresponds to componentType in the schema. Keys names can be chosen but there are some predefined constants which cover most common component types. Use these to prevent typos and inconsistencies.

A custom component is just a standard React component, that has access to two form state objects: meta and input.


What are meta and input?


meta

meta is an object which contains meta information about field with given name. There is a lot of information about every field.

Here is the full list of commonly used meta information.

{
error: any, // whatever your validation function returns
pristine: bool, // true if the current value is === to the initial value, false if the values are !==.
dirty: bool, // opposite of pristine
touched: bool, //true if this field has ever gained and lost focus. false otherwise. Useful for knowing when to display error messages.
valid: bool //true if this field has no validation or submission errors. false otherwise.
}

input

input is an object, which contains field values and methods that change form state.

See the selection of the most important attributes:

{
value: any, // any value of given form field. Its data type is based on field data type
name: string, // unique name of form field. Value will be accessible under this key in form state
onBlur: (event) => void, // function that should be triggered on field blur event
onChange: (value) => void, // function that changes value of field in formState. Should be called whenever you want to change value of field
onFocus: (event) => void, // function that should be triggered on field focus event
}

Every user interaction that updates field value in form state should also call input.onChange with correct value.


You have two options how to connect your component to these objects:

Recommended

First, you can use useFieldApi hook.

This hook needs name, in case of special input types which are using checked as the input value (checbkoxes, switches) you have to assign type: checkbox. The hook will return all field props, including input and meta.

import useFieldApi from '@data-driven-forms/react-form-renderer/use-field-api';
...
const { input, isDisabled, label, helperText, description, meta } = useFieldApi(props);

Or you can import FieldProvider component from Data Driven Forms. This component needs to obtain render or Component prop.

import FieldProvider from '@data-driven-forms/react-form-renderer/field-provider';
<FieldProvider Component={TextField}>
// or
<FieldProvider render={({input, meta, ...props}) => <TextField {...props} input={input} meta={meta}>}>

Data Driven Forms will render any component you pass to it, so you don't have to connect components to the form state in order to render it. Be aware that the component will receive metadata props such as component, validate, etc. You have to catch them before passing to other elements, otherwise it could throw DOM warnings.

const Title = ({component, name, label, ...props }) => <h1 id={name} {...props}>{label}</h1>

Using useFormApi you can get access to mutliple form methods without connecting a form field. Some most used methods are following:

renderForm

(fields) => React.Element

If you want to render fields from a component (tabs, subform, etc.) you can use renderForm(fields) function.

getState

() => FormState

Using getState components you get an access to the form state. Be aware of subscription - if your component is not subscribed to the form state, it won't be updated when the state is changed. See FormSpy.

change

(name, value) => void

You can change value of any field using this function.


To be able to use your component in the schema, you need to register the component in your component mapper.

import NewComponent from './new-component'
const componentMapper = {
'new-component': NewComponent
}

And then use the component mapper in the form renderer component:

import FormRenderer from '@data-driven-forms/react-form-renderer/form-renderer';
const Form = (props) => <FormRenderer
componentMapper={componentMapper}
{...props}
/>

Below, you can see an basic implementation of custom component mapper:


If you are building a new component mapper inside the Data Driven Forms repository, you can use a terminal command in the root folder to generate a basic mapper for you:

yarn generate-template

Or you can get the files directly on GitHub.