Form Field Widgets
Learn how to create form view field widgets for the frontend of your application.
Overview
Form view field widgets let you customize how fields are displayed inside a form view. They support both:
- edit mode via
editWidget - view mode via
viewWidget
You can use either:
- built-in widgets provided by the framework, or
- custom widgets that you create and register through the owning UI module manifest.
Example: display an integer field score as a slider using the built-in integerSlider widget.
{
"name": "model-form-view",
"layout": {
"type": "form",
"children": [
{
"type": "field",
"attrs": {
"name": "score",
"label": "Score",
"editWidget": "integerSlider"
}
}
]
}
}Tip
In the above example, the editWidget attribute specifies the widget to use in edit mode. While registering a widget, you can provide an alias such as integerSlider so the layout can reference the alias instead of the full component name.
Built-in Widgets
SolidX ships with a set of pre-built widgets for many field types. You can reference these directly in the layout JSON without writing or registering any code.
Edit Widgets (editWidget)
Used in edit mode via the editWidget attribute on a form field.
| Field Type | Description | Widget Name | Alias |
|---|---|---|---|
shortText | Default single-line text input | DefaultShortTextFormEditWidget | — |
shortText | Password-style masked input | MaskedShortTextFormEditWidget | maskedShortTextEdit |
shortText | Google Material Symbols icon picker dialog | SolidIconEditWidget | — |
longText | Default multi-line textarea | DefaultLongTextFormEditWidget | — |
longText | JSON editor with syntax highlighting | DynamicJsonEditorFormEditWidget | jsonEditor |
longText | Code editor with syntax highlighting | CodeEditorFormEditWidget | codeEditor |
integer | Default number input for integers | DefaultIntegerFormEditWidget | — |
integer | Range slider for integer values | SolidIntegerSliderStyleFormEditWidget | integerSlider |
decimal | Decimal number input | DefaultDecimalFormEditWidget | — |
email | Email input with format validation | DefaultEmailFormEditWidget | — |
password | Password input (edit mode) | DefaultPasswordFormEditWidget | — |
password | Password + confirm-password input (create mode) | DefaultPasswordFormCreateWidget | — |
time | Time picker | DefaultTimeFormEditWidget | — |
date | Date picker (calendar) | DefaultDateFormEditWidget | — |
datetime | Combined date and time picker | DefaultDateTimeFormEditWidget | — |
boolean | Dropdown select (Yes / No) | DefaultBooleanFormEditWidget | booleanSelectbox |
boolean | Checkbox style | SolidBooleanCheckboxStyleFormEditWidget | booleanCheckbox |
boolean | Toggle switch style | SolidBooleanSwitchStyleFormEditWidget | — |
json | JSON field editor | DefaultJsonFormEditWidget | — |
richText | WYSIWYG rich text editor | DefaultRichTextFormEditWidget | — |
selectionStatic | Autocomplete dropdown for static options | DefaultSelectionStaticAutocompleteFormEditWidget | — |
selectionStatic | Radio button group | SolidSelectionStaticRadioFormEditWidget | — |
selectionStatic | Segmented select buttons | SolidSelectionStaticSelectButtonFormEditWidget | — |
selectionDynamic | Autocomplete for API-driven dynamic options | DefaultSelectionDynamicFormEditWidget | — |
mediaSingle | Single file / image upload | DefaultMediaSingleFormEditWidget | — |
mediaMultiple | Multiple files / images upload | DefaultMediaMultipleFormEditWidget | — |
relation.many2one | Autocomplete relation selector | DefaultRelationManyToOneFormEditWidget | — |
relation.many2one | Short-text field wired to a many-to-one value | PseudoRelationManyToOneFormWidget | — |
relation.many2many | Many-to-many autocomplete chips | DefaultRelationManyToManyAutoCompleteFormEditWidget | — |
relation.many2many | Checkbox list for many-to-many selection | DefaultRelationManyToManyCheckBoxFormEditWidget | — |
relation.many2many | Toggle-switch grid for role permissions | RolePermissionsManyToManyFieldWidget | inputSwitch |
relation.one2many | Embedded editable table for one-to-many | DefaultRelationOneToManyFormEditWidget | — |
relation.one2many | Embedded list view of child records linked via a pseudo foreign-key relationship | PseudoRelationOneToManyFormWidget | — |
View Widgets (viewWidget)
Used in read-only mode via the viewWidget attribute on a form field.
| Field Type | Description | Widget Name | Alias |
|---|---|---|---|
shortText, longText, email | Default plain text display | DefaultShortTextFormViewWidget | — |
shortText | Masked text display | MaskedShortTextFormViewWidget | maskedShortTextForm |
shortText | Text with a colored initials avatar | SolidShortTextFieldAvatarWidget | — |
shortText | Renders a stored icon name as a Material Symbols icon | SolidIconViewWidget | — |
integer | Plain integer display | DefaultIntegerFormViewWidget | — |
decimal | Plain decimal display | DefaultDecimalFormViewWidget | — |
time | Formatted time display | DefaultTimeFormViewWidget | — |
date | Formatted date display | DefaultDateFormViewWidget | — |
datetime | Formatted date and time display | DefaultDateTimeFormViewWidget | — |
boolean | Boolean display | DefaultBooleanFormViewWidget | — |
json | JSON read-only display | DefaultJsonFormViewWidget | — |
longText | Read-only JSON viewer with syntax highlighting | DynamicJsonEditorFormViewWidget | jsonViewer |
password | Masked password display | DefaultPasswordFormViewWidget | — |
richText | Rendered rich text (HTML) | DefaultRichTextFormViewWidget | — |
selectionStatic | Static selection label display | DefaultSelectionStaticFormViewWidget | — |
selectionDynamic | Dynamic selection label display | DefaultSelectionDynamicFormViewWidget | — |
mediaSingle | Single media preview | DefaultMediaSingleFormViewWidget | — |
mediaMultiple | Multiple media thumbnails | DefaultMediaMultipleFormViewWidget | — |
relation.many2one | Many-to-one relation label | DefaultRelationManyToOneFormViewWidget | — |
relation | Relation value(s) rendered as avatar chips | SolidRelationFieldAvatarFormWidget | — |
relation.one2many | Read-only embedded table for one-to-many | DefaultRelationOneToManyFormViewWidget | — |
Creating a Custom Widget
1. Create the Widget Component
Here is an example of an integer slider widget. This widget allows users to select an integer value using a slider.
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">
{/* render your slider here */}
{isFormFieldValid(formik, fieldLayoutInfo.attrs.name) && (
<div className="absolute mt-2">
<Message severity="error" text={formik?.errors[fieldLayoutInfo.attrs.name]?.toString()} />
</div>
)}
</div>
</div>
);
};File location:
solid-ui/src/<module-name>/admin-layout/<model-name>/extension-components/SolidIntegerSliderStyleFormEditWidget.tsx2. Register the Widget
Register form field widgets in the owning module manifest.
import { ExtensionComponentTypes, type SolidUiModule } from "@solidxai/core-ui";
import { SolidIntegerSliderStyleFormEditWidget } from "./admin-layout/institute/extension-components/SolidIntegerSliderStyleFormEditWidget";
const instituteUiModule = {
name: "institute",
extensionComponents: [
{
name: "SolidIntegerSliderStyleFormEditWidget",
component: SolidIntegerSliderStyleFormEditWidget,
type: ExtensionComponentTypes.formFieldEditWidget,
aliases: ["integerSlider"],
},
],
} satisfies SolidUiModule;
export default instituteUiModule;Manifest location:
solid-ui/src/<module-name>/<module-name>.ui-module.ts3. Use in Layout
Now you can configure the widget within the form view layout configuration in the module metadata schema JSON file:
{
"name": "institute-form-view",
"layout": {
"type": "form",
"children": [
{
"type": "field",
"attrs": {
"name": "score",
"label": "Score",
"editWidget": "integerSlider"
}
}
]
}
}Metadata location:
solid-api/module-metadata/<module-name>/<module-name>-metadata.jsonHow It Works
- SolidX loads the form layout in edit mode.
- It identifies fields with an
editWidgetorviewWidget. - It resolves the registered widget component by name or alias.
- The widget is rendered with props of type
SolidFormFieldWidgetProps. - The widget applies your custom rendering logic.
- Default widgets are also rendered using the same mechanism.
Widget Props Contract
export type SolidFormFieldWidgetProps = {
formik: any;
fieldContext?: SolidFieldProps;
};
export type SolidFieldProps = {
solidFormViewMetaData: any;
fieldMetadata: any;
field: any;
data: any;
modelName?: any;
readOnly?: any;
viewMode?: any;
onChange?: any;
onBlur?: any;
parentData?: any;
};Guidance:
- use
fieldContext.fieldMetadatafor field constraints and display metadata - use
fieldContext.fieldfor layout attributes such as label and widget choice - use
formik.valuesandformik.setFieldValue(...)for form state changes - respect
readOnly, validation, and required-state behavior
View Widgets (Read-Only Mode)
Similarly, you can create view widgets for read-only mode using viewWidget instead of editWidget.
Example:
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>
);
};Register a read-only widget in the same manifest using ExtensionComponentTypes.formFieldViewWidget.
API Integration Inside Widgets
Form field widgets can use either of the supported SolidX frontend API integration styles.
Option A: Solid HTTP Helpers
Use solidGet, solidPost, solidPut, solidPatch, solidDelete, or solidAxios when the widget needs local API interaction without shared cached state.
Option B: Redux / RTK Query
If the widget participates in a wider module-owned data flow, place RTK Query APIs, reducers, and middleware under:
solid-ui/src/<module-name>/redux/
and register them through the same UI module manifest.
See also: Redux Module Integration and Solid HTTP API
Related
- List View Field Widgets — built-in and custom widgets for list column display
- Kanban Card Widget — widgets for kanban card fields
- Custom Widgets — general guide to registering extension components