Writing Custom Components
Custom components are written in the same way as regular React components. This document introduces the basic concepts and example code needed for writing custom components.
Basic Structure
The basic structure of a custom component is as follows:
import { memo, ReactElement } from 'react';
import { CustomComponentRenderProps, useComponentState, useLogger } from '@hops/custom-component';
import { FormControl, FormLabel, Input } from '@hops/design-system';
interface OwnProps {
label: string;
defaultValue: string;
}
function MyComponent(props: CustomComponentRenderProps<OwnProps>): ReactElement {
const { label, defaultValue } = props;
const logger = useLogger();
const [value, setValue] = useComponentState<string>('inputValue', defaultValue);
return (
<FormControl>
<FormLabel>{label}</FormLabel>
<Input
value={value}
onChange={(e) => {
setValue(e.target.value);
logger.debug(`onChange called: ${e.target.value}`);
}}
/>
</FormControl>
);
}
export default memo(MyComponent);
Component Writing Steps
1. Define Props
Custom components define props to receive from the outside through the OwnProps
interface:
interface OwnProps {
// Props that users can set in the editor
label: string;
placeholder: string;
required: boolean;
}
These props can be set by users in the editor and used within the component.
2. Manage State
The state of the component is managed using the useComponentState
hook:
const [value, setValue] = useComponentState<string>('fieldValue', defaultValue);
The state defined by useComponentState
when implementing a custom component is also externally accessible.
Access the state of a custom component with an accessor of the form component_name.state_name
where needed.
customComponent1.fieldValue;
State managed in this way can be accessed and used by other components or workflows. Of course, you can also manage state that is only used internally using React's useState.
3. Implement UI
Implement UI using JSX like a regular React component:
return (
<FormControl required={required}>
<FormLabel>{label}</FormLabel>
<Input value={value} placeholder={placeholder} onChange={(e) => setValue(e.target.value)} />
</FormControl>
);
Using Hops design system components (@hops/design-system
) helps maintain consistent design.