Form View Field Widgets
Overview
Form view widgets allow you to customize how fields are displayed in a form view.
They support both view mode and edit mode.
You can use either:
- Built-in widgets (provided by the framework), or
- Custom widgets (that you create).
Example: Display an integer field score as a slider using the built-in integerSlider widget.
Using Built-in Widget
{
"name": "model-form-view",
...
"layout": {
"type": "form",
...
"children": [
{
"type": "field",
"attrs": {
"name": "score",
"label": "Score",
"editWidget": "integerSlider"
}
}
]
}
}
In the above example, the editWidget attribute specifies the widget to use in edit mode. While registering a widget, you can provide an alias (like integerSlider) to reference it easily in the layout instead of the full component name e.g. SolidIntegerSliderStyleFormEditWidget.
Creating a Custom Widget
1. Create the Widget Component
Here’s an example of an integer slider widget. This widget allows users to select an integer value using a slider.
SolidIntegerSliderStyleFormEditWidget
import { SolidFormFieldWidgetProps } from "@solidxai/core-ui";
export const SolidIntegerSliderStyleFormEditWidget = ({ formik, fieldContext }: SolidFormFieldWidgetProps) => {
const fieldMetadata = fieldContext.fieldMetadata;
const fieldLayoutInfo = fieldContext.field;
const fieldLabel = fieldLayoutInfo.attrs.label ?? fieldMetadata.displayName;
const showFieldLabel = fieldLayoutInfo?.attrs?.showLabel;
const min = fieldMetadata.min || 0;
const max = fieldMetadata.max || 5;
const fieldName = fieldLayoutInfo.attrs.name;
const currentValue = Number(formik.values[fieldName] ?? min);
const isFormFieldValid = (formik: any, fieldName: string) =>
formik.touched[fieldName] && formik.errors[fieldName];
return (
<div className="w-full" style={{ height: '60px' }}>
{showFieldLabel !== false && (
<div className="font-medium mb-2">
{fieldLabel}
{fieldMetadata.required && <span className="text-red-500"> *</span>}
</div>
)}
<div className="relative h-12">
<Range
step={1}
min={min}
max={max}
values={[currentValue]}
onChange={(values) => {
formik.setFieldValue(fieldName, values[0]);
}}
renderTrack={({ props, children }) => {
const percent = ((currentValue - min) / (max - min)) * 100;
return (
<div {...props} style={{
...props.style,
height: "10px",
width: "100%",
borderRadius: "8px",
backgroundColor: "var(--primary-light-color)",
position: "relative"
}}>
<div style={{
position: "absolute",
height: "100%",
width: `${percent}%`,
backgroundColor: "var(--primary-color)",
borderRadius: "5px",
top: 0,
left: 0
}} />
{children}
</div>
)
}}
renderThumb={({ props }) => (
<div {...props} key={props.key} style={{
...props.style,
height: "18px",
width: "18px",
border: "4px solid var(--surface-0)",
borderRadius: '50%',
backgroundColor: "var(--primary-color)"
}} />
)}
/>
<div className="flex align-item-center justify-content-between mt-2">
{Array.from({ length: max - min + 1 }, (_, i) => {
const num = i + min;
return (
<span key={num} className="text-sm">
{num === 0 ? '' : num}
</span>
);
})}
</div>
{isFormFieldValid(formik, fieldLayoutInfo.attrs.name) && (
<div className="absolute mt-2">
<Message severity="error" text={formik?.errors[fieldLayoutInfo.attrs.name]?.toString()} />
</div>
)}
</div>
</div>
);
}
File Path:
As per project structure, place the widget component in the extensions folder:
/solid-ui/app/admin/extensions/SolidIntegerSliderStyleFormEditWidget.tsx
2. Register the Widget
Widgets must be registered in solid-extensions.ts:
Registering the Widget
registerExtensionComponent(
"SolidIntegerSliderStyleFormEditWidget", // component name
SolidIntegerSliderStyleFormEditWidget, // component reference
["integerSlider"] // alias name
);
File Path:
/solid-ui/app/admin/extensions/solid-extensions.ts
3. Use in Layout
Now you can configure the widget within the form view layout configuration in the module metadata schema JSON file:
Using Custom Widget in Layout
{
"name": "institute-form-view",
... // other attributes
"layout": {
"type": "form",
... // other attributes
"children": [
{
"type": "field",
"attrs": {
"name": "score",
"label": "Score",
"editWidget": "integerSlider"
}
}
]
}
}
File Path:
/solid-api/module-metadata/<module-name>/<module-name>-metadata.json
How It Works
- SolidX loads the form layout in edit mode.
- It identifies fields with an
editWidget. - It dynamically imports the corresponding widget component.
- The widget is rendered with props of type
SolidFormFieldWidgetProps:
SolidFormFieldWidgetProps
export type SolidFormFieldWidgetProps = {
formik: any; // Formik instance for form state management
fieldContext?: SolidFieldProps;
}
export type SolidFieldProps = {
solidFormViewMetaData: any; // Metadata of the form view
fieldMetadata: any, // Metadata of the specific field
field: any, // Layout info of the field
data: any, // Current data of the form
modelName?: any, // Name of the model
readOnly?: any, // Is the field read-only
viewMode?: any // Is the form in view mode
onChange?: any, // Callback for change events
onBlur?: any, // Callback for blur events
// Used in embedded views i.e for relation fields
parentData?: any, // Data of the parent entity
}
- The widget then applies your custom rendering logic.
- Default widgets are also rendered using the same mechanism.
View Widgets (Read-Only Mode)
Similarly, you can create view widgets for read-only mode using viewWidget instead of editWidget.
Example: Boolean View Widget
CustomBooleanFormViewWidget
export const CustomBooleanFormViewWidget = ({ formik, fieldContext }: SolidFormFieldWidgetProps) => {
const fieldMetadata = fieldContext.fieldMetadata;
const fieldLayoutInfo = fieldContext.field;
const fieldLabel = fieldLayoutInfo.attrs.label ?? fieldMetadata.displayName;
return (
<div className="mt-2 flex-column gap-2">
<p className="m-0 form-field-label font-medium">{fieldLabel}</p>
<p className="m-0">
{formik.values[fieldLayoutInfo.attrs.name] === true ||
formik.values[fieldLayoutInfo.attrs.name] === "true"
? "Yes" : "No"}
</p>
</div>
);
}
This allows you to render a boolean field as "Yes/No" in view mode.
With this approach, you can seamlessly extend SolidX form views using custom widgets for both edit and view modes.