Skip to content

Item Renderers

Item renderers are framework-specific functions or components that the form engine invokes to render each item of a dropdown, list, or radiogroup. The engine forwards an ItemRenderContext<T> object that carries the raw item plus useful metadata (selected, disabled, focused, index).

Each framework adapts the same ItemRenderContext<T> to its idiomatic shape:

FrameworkTypeWhat the engine passes
ReactReactItemRenderer<T>A React.ComponentType<ItemRenderContext<T>> — the context fields arrive as props.
AngularAngularItemRenderer<T>A component class structurally matching AngularItemRenderContext<T> — one signal input() per context field.
LitLitItemRenderer<T>A (ctx: ItemRenderContext<T>) => TemplateResult — called as a function, not a custom element.
VueVueItemRenderer<T>A Component<Partial<ItemRenderContext<T>>> — the context fields arrive as props on the SFC.
Vanilla JS(ctx) => HTMLElementA plain function called with ItemRenderContext<T> that returns a DOM node — like Lit’s, but returning real DOM instead of a TemplateResult.

The shared context shape comes from @golemui/core:

export interface ItemRenderContext<T extends ItemRenderItemData> {
template: T;
value: string | number;
index: number;
selected?: boolean;
disabled?: boolean;
focused?: boolean;
}

template is the raw item from the widget’s items array. The other fields reflect the live state of the option in the rendered list.

import type { ReactItemRenderer } from '@golemui/react';
type Country = { id: string; flag: string; label: string };
export const CountryItemRenderer: ReactItemRenderer<Country> = ({
template,
index,
selected,
disabled,
focused,
}) => (
<div
className={`country-item ${selected ? 'country-item--selected' : ''} ${
disabled ? 'country-item--disabled' : ''
} ${focused ? 'country-item--focused' : ''} ${index % 2 ? 'country-item--odd' : ''}`}
>
<span className="country-item__flag">{template.flag}</span>
<span className="country-item__label">{template.label}</span>
</div>
);

Props are the full ItemRenderContext<T> — destructure whichever fields you need.

The widget references the renderer by name through its itemRenderer prop. Where the renderer map lives depends on the path:

In the Programmatic API the renderer map goes inside formConfig.itemRenderers:

import { gui } from '@golemui/gui-shared';
import { CountryItemRenderer } from './country-item-renderer';
const config = {
formDef: [
gui.inputs.dropdown('country', {
items: [
/* … */
],
itemRenderer: 'countryItemRenderer',
}),
],
formConfig: { itemRenderers: { countryItemRenderer: CountryItemRenderer } },
};
// <GuiForm config={config} />

In the JSON path the renderer map is a top-level property of the config object — there is no formConfig wrapper for JSON forms. The JSON references the renderer by name on the widget.

{
"form": [
{
"kind": "input",
"type": "dropdown",
"path": "country",
"items": [],
"itemRenderer": "countryItemRenderer"
}
]
}
import { CountryItemRenderer } from './country-item-renderer';
import formDef from './my-form.json';
const config = {
formDef,
itemRenderers: { countryItemRenderer: CountryItemRenderer },
};
// <GuiForm config={config} />