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

SolidX loads the form layout in edit mode.

It identifies fields with an editWidget or viewWidget.

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.

Built-in and Custom Widgets Share the Same Rendering Path

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

Use this option when the form field widget belongs to a module-owned API strategy and should participate in shared cached state, invalidation, or coordinated refresh flows.

Place RTK Query APIs, reducers, and middleware under solid-ui/src/<module-name>/redux/, and register them through the same module manifest.

See Redux Module Integration for the full module-owned pattern. For direct API helpers, see Solid HTTP API.