SolidX
ReferenceExtending SolidXFrontend Customization

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 TypeDescriptionWidget NameAlias
shortTextDefault single-line text inputDefaultShortTextFormEditWidget
shortTextPassword-style masked inputMaskedShortTextFormEditWidgetmaskedShortTextEdit
shortTextGoogle Material Symbols icon picker dialogSolidIconEditWidget
longTextDefault multi-line textareaDefaultLongTextFormEditWidget
longTextJSON editor with syntax highlightingDynamicJsonEditorFormEditWidgetjsonEditor
longTextCode editor with syntax highlightingCodeEditorFormEditWidgetcodeEditor
integerDefault number input for integersDefaultIntegerFormEditWidget
integerRange slider for integer valuesSolidIntegerSliderStyleFormEditWidgetintegerSlider
decimalDecimal number inputDefaultDecimalFormEditWidget
emailEmail input with format validationDefaultEmailFormEditWidget
passwordPassword input (edit mode)DefaultPasswordFormEditWidget
passwordPassword + confirm-password input (create mode)DefaultPasswordFormCreateWidget
timeTime pickerDefaultTimeFormEditWidget
dateDate picker (calendar)DefaultDateFormEditWidget
datetimeCombined date and time pickerDefaultDateTimeFormEditWidget
booleanDropdown select (Yes / No)DefaultBooleanFormEditWidgetbooleanSelectbox
booleanCheckbox styleSolidBooleanCheckboxStyleFormEditWidgetbooleanCheckbox
booleanToggle switch styleSolidBooleanSwitchStyleFormEditWidget
jsonJSON field editorDefaultJsonFormEditWidget
richTextWYSIWYG rich text editorDefaultRichTextFormEditWidget
selectionStaticAutocomplete dropdown for static optionsDefaultSelectionStaticAutocompleteFormEditWidget
selectionStaticRadio button groupSolidSelectionStaticRadioFormEditWidget
selectionStaticSegmented select buttonsSolidSelectionStaticSelectButtonFormEditWidget
selectionDynamicAutocomplete for API-driven dynamic optionsDefaultSelectionDynamicFormEditWidget
mediaSingleSingle file / image uploadDefaultMediaSingleFormEditWidget
mediaMultipleMultiple files / images uploadDefaultMediaMultipleFormEditWidget
relation.many2oneAutocomplete relation selectorDefaultRelationManyToOneFormEditWidget
relation.many2oneShort-text field wired to a many-to-one valuePseudoRelationManyToOneFormWidget
relation.many2manyMany-to-many autocomplete chipsDefaultRelationManyToManyAutoCompleteFormEditWidget
relation.many2manyCheckbox list for many-to-many selectionDefaultRelationManyToManyCheckBoxFormEditWidget
relation.many2manyToggle-switch grid for role permissionsRolePermissionsManyToManyFieldWidgetinputSwitch
relation.one2manyEmbedded editable table for one-to-manyDefaultRelationOneToManyFormEditWidget
relation.one2manyEmbedded list view of child records linked via a pseudo foreign-key relationshipPseudoRelationOneToManyFormWidget

View Widgets (viewWidget)

Used in read-only mode via the viewWidget attribute on a form field.

Field TypeDescriptionWidget NameAlias
shortText, longText, emailDefault plain text displayDefaultShortTextFormViewWidget
shortTextMasked text displayMaskedShortTextFormViewWidgetmaskedShortTextForm
shortTextText with a colored initials avatarSolidShortTextFieldAvatarWidget
shortTextRenders a stored icon name as a Material Symbols iconSolidIconViewWidget
integerPlain integer displayDefaultIntegerFormViewWidget
decimalPlain decimal displayDefaultDecimalFormViewWidget
timeFormatted time displayDefaultTimeFormViewWidget
dateFormatted date displayDefaultDateFormViewWidget
datetimeFormatted date and time displayDefaultDateTimeFormViewWidget
booleanBoolean displayDefaultBooleanFormViewWidget
jsonJSON read-only displayDefaultJsonFormViewWidget
longTextRead-only JSON viewer with syntax highlightingDynamicJsonEditorFormViewWidgetjsonViewer
passwordMasked password displayDefaultPasswordFormViewWidget
richTextRendered rich text (HTML)DefaultRichTextFormViewWidget
selectionStaticStatic selection label displayDefaultSelectionStaticFormViewWidget
selectionDynamicDynamic selection label displayDefaultSelectionDynamicFormViewWidget
mediaSingleSingle media previewDefaultMediaSingleFormViewWidget
mediaMultipleMultiple media thumbnailsDefaultMediaMultipleFormViewWidget
relation.many2oneMany-to-one relation labelDefaultRelationManyToOneFormViewWidget
relationRelation value(s) rendered as avatar chipsSolidRelationFieldAvatarFormWidget
relation.one2manyRead-only embedded table for one-to-manyDefaultRelationOneToManyFormViewWidget

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.tsx

2. 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.ts

3. 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.json

How It Works

  1. SolidX loads the form layout in edit mode.
  2. It identifies fields with an editWidget or viewWidget.
  3. It resolves the registered widget component by name or alias.
  4. The widget is rendered with props of type SolidFormFieldWidgetProps.
  5. The widget applies your custom rendering logic.
  6. 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.fieldMetadata for field constraints and display metadata
  • use fieldContext.field for layout attributes such as label and widget choice
  • use formik.values and formik.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