Skip to content

Custom Widgets

Each shortcut group exposes a .custom() factory for widgets you’ve implemented yourself. The shape mirrors the built-in shortcuts but takes the widget type as the first argument.

import { gui } from '@golemui/gui-shared';
// Custom layout
gui.layouts.custom(
'productCard',
[
/* children */
],
{ title: 'My Product' },
);
// Custom input
gui.inputs.custom('productRating', 'product.rating', {
maxRating: 10,
validator: { type: 'number', required: true },
});
// Custom display
gui.displays.custom('productDescription', {
img: 'assets/product.png',
description: '### Cool product',
});
// Custom action
gui.actions.custom('productShare', { onClick: () => 'shareEvent' });

The first arg is the widget type string — it must match the key you register in formConfig.widgetLoaders.

Custom inputs accept a validator prop typed as the union of all built-in validator types. Use { type: 'string'/'number'/'boolean'/'array'/'custom', ... }.

Custom widgets really shine when you compose them. The Product Card below — built throughout the Extending GolemUI tutorial — combines all four kinds in a single form: a custom layout (productCard) wrapping a custom display (productDescription), a custom input (productRating), and a custom action (productShare). It also mixes in built-in widgets (textarea, button) without any special wiring.

Here’s the full form definition that produces the demo:

import { gui } from '@golemui/gui-shared';
const formDef = [
gui.layouts.custom(
'productCard',
[
gui.displays.custom('productDescription', {
img: 'https://picsum.photos/seed/golemui/240/240',
description: '### GolemUI\nThe declarative form engine.',
}),
gui.inputs.custom('productRating', 'product.rating', {
label: 'Your rating',
maxRating: 10,
validator: {
type: 'number',
required: true,
messages: { required: 'Please rate the product before submitting' },
},
}),
gui.inputs.textarea('product.comment', {
label: 'Your comment',
hint: 'Enter your comment (maximum 500 characters)',
placeholder: 'Let us know why you love our product',
counterMode: 'current',
validator: {
required: true,
maxLength: 500,
messages: {
required: 'Please leave a comment with your rating',
maxLength:
'Your comment is too long — keep it under 500 characters',
},
},
}),
gui.actions.custom('productShare', {
label: 'Share',
networks: [
{
id: 'twitter',
label: 'X',
icon: 'https://cdn.simpleicons.org/x/333',
},
{
id: 'facebook',
label: 'Facebook',
icon: 'https://cdn.simpleicons.org/facebook/1877F2',
},
{
id: 'reddit',
label: 'Reddit',
icon: 'https://cdn.simpleicons.org/reddit/FF4500',
},
],
onClick: () => 'shareEvent',
}),
gui.actions.button({
label: 'Submit',
icon: 'save',
iconPosition: 'right',
actionType: 'submit',
}),
],
{ title: 'Rate Our Product' },
),
];

And the result — fully interactive:

The full per-framework implementation — React hooks, Angular adapters, Lit elements, plus how to register and event-handle each kind — lives in Extending GolemUI / Widgets Overview and the four kind-specific chapters under it.