Custom Widgets
Build and register form-view custom widgets in SolidX.
Overview
Custom widgets in SolidX are form-view extension components rendered through layout nodes with:
{
"type": "custom"
}Use them when you want a targeted custom UI block inside a generated form view.
This page is specifically about form-view custom nodes. It is not the reference page for:
- form buttons
- list buttons
- row actions
- field widgets
- kanban card widgets
Location and Registration
For model-scoped widgets, use:
solid-ui/src/<module-name>/admin-layout/<model-name>/extension-components/
Register them in the owning module manifest:
solid-ui/src/<module-name>/<module-name>.ui-module.ts
with:
import { ExtensionComponentTypes, type SolidUiModule } from "@solidxai/core-ui";
import { MyCustomWidget } from "./admin-layout/book/extension-components/MyCustomWidget";
const libraryUiModule = {
name: "library",
extensionComponents: [
{
name: "MyCustomWidget",
component: MyCustomWidget,
type: ExtensionComponentTypes.formWidget,
},
],
} satisfies SolidUiModule;
export default libraryUiModule;Layout Wiring
Reference your registered widget in form-view layout metadata:
{
"type": "custom",
"attrs": {
"name": "book-custom-1",
"widget": "MyCustomWidget"
}
}Props Contract
Custom widgets receive a SolidFormWidgetProps-style payload in form contexts, including:
fieldformDataviewMetadatafieldsMetadataformViewData
Always derive context from incoming props (for example formData, field, or metadata) instead of hardcoded values.
API Calls in Widgets
When widgets need backend calls, Solid supports both of these patterns:
- Direct Solid HTTP helpers from
@solidxai/core-ui - Module-owned Redux / RTK Query integration under
solid-ui/src/<module-name>/redux/
Option A: Solid HTTP Helpers
Use:
solidGet,solidPost,solidPut,solidPatch,solidDelete,solidAxios
Guidelines:
- Use endpoint paths like
/resource(no hardcoded/api). - Handle loading/error state explicitly in component logic.
- For list/filter requests, use
qs.stringify(..., { encodeValuesOnly: true })or Axiosparams. - Use context IDs/values from props instead of constants.
Option B: Redux / RTK Query
If the app prefers store-backed integration, keep RTK Query APIs in the owning module's redux/ folder and register the module's reducers and middleware in <module-name>.ui-module.ts.
Choose this when you want shared API state, caching, invalidation, and generated hooks.
See Redux Module Integration for the full pattern.
Example
import { useEffect, useState } from "react";
import { solidGet } from "@solidxai/core-ui";
import type { SolidFormWidgetProps } from "@solidxai/core-ui";
export function TitleStatsWidget({ formData }: SolidFormWidgetProps) {
const [count, setCount] = useState(0);
useEffect(() => {
const title = String(formData?.title || "");
setCount(title.length);
}, [formData?.title]);
return <span>Title length: {count}</span>;
}
export async function loadTitleHints(query: string) {
const resp = await solidGet("/title-hints", { params: { query } });
return resp?.data?.data?.records || [];
}