Build a custom component
Boomi Flow enables you to create your own custom components, allowing you to tailor solutions precisely to your requirements.
There are two types of custom components: standard Custom Components and Column Custom Components. Column custom components are designed specifically for use in tables or datagrids. Unlike standard components, they do not use PageElementProps; instead, they use CustomCellElementProps<TRow>, which provides the necessary structure and context for rendering within a column.
Flow custom components are made up of a JavaScript module file that exports a standard React component. You can also include other files like CSS stylesheets and images if you want. To learn how to add these files into Flow, check out Add a custom component.
To become familiar with React, you can access comprehensive information about the React JavaScript framework on their official website.
Getting data into your components
Flow data is supplied to your components using React props. You can find a full list of props available to Flow components in the reference documentation under PageElementProps for custom components and under CustomCellElementProps for column components.
For custom components the element prop contains data related to the current component instance being rendered, like the current value, whether the component is enabled, and other attributes set at design time.
For column components, only current value props are available, and are accessed directly on CustomCellElementProps.
There are 2 distinct ways that your Value’s current value can be stored. Object and List Values provide their data within the objectData property. For more information, refer to the Advanced example below. In contrast, all other Values, which are classified as "primitives", provide their data in the contentValue property. Details on this can be found in the Basic example below.
Updating component state
To update the state value associated with the component, use the updateElement function provided in the props. This function accepts an object that must include the element’s ID (found in props), a partial element object with any updated properties, and optionally, whether the update should trigger page conditions.
Basic example
This is a basic input component that updates the state content value as a user types.
When creating the Component in Flow for this example, make sure to select the Save the component state into option under Configuration Editors section. This will allow you to select a Value when you add this component to a page.
When selecting a Value, make sure to pick any Value kind except Object/List.
const { React } = window.boomi.flow;
const InputText = ({ element, updateElement }) => {
const onChange = ({ target: { value } }) =>
updateElement({
elementId: element.id,
elementPartial: {
contentValue: value,
},
});
return React.createElement('input', {
className: 'input',
value: element.contentValue,
onChange,
placeholder: element.hintValue ?? '',
readOnly: !element.isEditable,
disabled: !element.isEnabled,
required: element.isRequired,
});
};
export default InputText;
Advanced example
This is a more advanced example that displays a list of inputs and updates each list item as the user types into one of the input elements.
The Flow list value used in this example is a list of items with a type of “Input”. This custom Flow type has a single property named “Value” that we’ll use for the value of each input in the list.
Flow describes list data in a format called ObjectData. In our case, this data is an array of ObjectData objects that describe each “Input” item in the list.
When creating the Component in Flow for this example, make sure to select the Save the component state into option under Configuration Editors section. This will allow you to select a Value when you add this component to a page.
When selecting a Value, make sure to pick an Object/List kind Value that uses a Type with a property named Value.
const { React } = window.boomi.flow;
const InputList = ({ element, updateElement }) => {
const onChange = (externalId, value) => {
const updatedList = element.objectData.map((item) => {
/** Find the item by matching its external ID */
if (item.externalId === externalId) {
const updatedProperties = item.properties.map((property) => {
/** Find the property inside the item by matching its developerName */
if (property.developerName === 'Value') {
return {
...property,
/** Update the property's contentValue */
contentValue: value,
};
}
return item;
});
return {
...item,
properties: updatedProperties,
};
}
return item;
});
updateElement({
elementId: element.id,
elementPartial: {
objectData: updatedList,
/** In order to save the updated items they must also be copied to the selectedItems */
selectedItems: updatedList,
},
});
};
return React.createElement(
'ol',
{},
element.objectData.map((item) =>
React.createElement(
'li',
{},
React.createElement('input', {
className: 'input',
/** Find the 'Value' property object and use its contentValue */
value: item.properties.find(
(property) => property.developerName === 'Value'
).contentValue,
onChange: (event) =>
onChange(item.externalId, event.target.value),
placeholder: element.hintValue ?? '',
readOnly: !element.isEditable,
disabled: !element.isEnabled,
required: element.isRequired,
})
)
)
);
};
export default InputList;