Skip to content

Widget Loaders

Widget loaders are a Record<string, () => Promise<unknown>> map that tells the form engine how to lazy-load each widget kind. The map key is the widget type (e.g. 'textinput', 'dropdown') and the value is an async loader that returns the widget implementation.

Each framework adapter ships the GolemUI widget set as a default widgetLoaders export. You don’t need to pass them yourself<GuiForm> includes the framework defaults automatically. You only wire widgetLoaders (DX path) or customWidgetLoaders (JSON path) when you have your own custom widgets to register.

The built-in widget set covers every input, layout, display, and action widget. A form that uses only built-in widgets needs nothing but formDef:

import { gui } from '@golemui/gui-shared';
import { GuiForm } from '@golemui/gui-react';
const formDef = [gui.inputs.textInput('username')];
export function MyForm() {
return <GuiForm config={{ formDef }} />;
}
import { GuiForm } from '@golemui/gui-react';
import formDef from './my-form.json';
export function MyForm() {
return <GuiForm config={{ formDef }} />;
}

Pass only your own loader entries — <GuiForm> merges them with the built-in defaults internally. The key (e.g. productCard) must match the type field on the widget instances in your formDef.

In the Programmatic API your loaders go into formConfig.widgetLoaders.

import { gui } from '@golemui/gui-shared';
import { GuiForm } from '@golemui/gui-react';
const config = {
formDef: [
gui.layouts.custom('productCard', [/* children */], { title: 'My product' }),
],
formConfig: {
widgetLoaders: {
productCard: async () =>
(await import('./widgets/ProductCard')).ProductCard,
},
},
};
export function MyForm() {
return <GuiForm config={config} />;
}

In the JSON path your loaders go into customWidgetLoaders on the config object. The JSON itself references the widget by "type": "productCard".

{
"form": [
{
"kind": "layout",
"type": "productCard",
"props": { "title": "My product" },
"items": []
}
]
}
import { GuiForm } from '@golemui/gui-react';
import formDef from './my-form.json';
const config = {
formDef,
customWidgetLoaders: {
productCard: async () => (await import('./widgets/ProductCard')).ProductCard,
},
};
export function MyForm() {
return <GuiForm config={config} />;
}

Widget loaders use dynamic import() so custom widgets are lazy-loaded — they’re only fetched when the form engine encounters them.