Skip to main content

Creating widgets

Sometimes you need to make custom widgets if you need more control over the markup or need to introduce new functionality into your forms.

A very basic example

The example below is the smallest possible working example for creating a widget:

import React from "react";
import { createForm, textField, StatefulFormView, widget } from "@fab4m/fab4m";
import "@fab4m/fab4m/css/basic/basic.css";

const customTextFieldWidget = widget({
type: {
widget: (props) => {
return (
<input
type="text"
name={props.name}
id={props.id}
required={props.component.required}
disabled={props.component.disabled}
value={props.value ?? ""}
onChange={(e) => {
props.onChange(e.currentTarget.value);
}}
{...props.attributes}
/>
);
},
},
});

const form = createForm({
name: textField({
label: "Your name",
required: true,
widget: customTextFieldWidget,
}),
});

export default function CustomWidgetExample() {
return <StatefulFormView form={form} hideSubmit={true} />;
}

Using the fab4m wrapper

If you want to provide most of the basic functionality that is provided with the standard fab4m widgets you can wrap your widget in the FormComponentWrapper component.

import React from "react";
import {
createForm,
textField,
StatefulFormView,
widget,
FormComponentWrapper,
} from "@fab4m/fab4m";
import "@fab4m/fab4m/css/basic/basic.css";

const fab4mWidget = widget({
type: {
widget: (props) => {
return (
<FormComponentWrapper {...props}>
<input
type="text"
name={props.name}
id={props.id}
required={props.component.required}
disabled={props.component.disabled}
value={props.value ?? ""}
onChange={(e) => {
props.onChange(e.currentTarget.value);
}}
{...props.attributes}
/>
</FormComponentWrapper>
);
},
},
});

const form = createForm({
name: textField({
label: "Your name",
required: true,
widget: fab4mWidget,
}),
});

export default function CustomWidgetExample() {
return <StatefulFormView form={form} hideSubmit={true} />;
}

Typescript support

You can define the data type that the widget is operating on, as well as the settings type that the widget is using (see the next section):

import React from "react";
import { createForm, textField, StatefulFormView, widget } from "@fab4m/fab4m";
import "@fab4m/fab4m/css/basic/basic.css";

const customTextFieldWidget = widget<string>({
type: {
widget: (props) => {
return (
<input
type="text"
name={props.name}
id={props.id}
required={props.component.required}
disabled={props.component.disabled}
value={props.value ?? ""}
onChange={(e) => {
props.onChange(e.currentTarget.value);
}}
{...props.attributes}
/>
);
},
},
});

const form = createForm({
name: textField({
label: "Your name",
required: true,
widget: customTextFieldWidget,
}),
});

export default function CustomWidgetExample() {
return <StatefulFormView form={form} hideSubmit={true} />;
}

Providing settings for your widget

You can define settings for your widget, in those situations it's best to provide a function to create your widget with the appropriate settings.

import React from "react";
import { createForm, textField, StatefulFormView, widget } from "@fab4m/fab4m";
import "@fab4m/fab4m/css/basic/basic.css";

type CustomWidgetSettings = {
color: string;
};

function myCustomWidget(settings: CustomWidgetSettings) {
return widget<string, CustomWidgetSettings>({
type: {
widget: (props) => {
return (
<input
type="text"
name={props.name}
id={props.id}
style={{ background: props.settings.color }}
required={props.component.required}
disabled={props.component.disabled}
value={props.value ?? ""}
onChange={(e) => {
props.onChange(e.currentTarget.value);
}}
{...props.attributes}
/>
);
},
},
settings,
});
}

const form = createForm({
name: textField({
label: "Your name",
required: true,
widget: myCustomWidget({ color: "blue" }),
}),
});

export default function CustomWidgetExample() {
return <StatefulFormView form={form} hideSubmit={true} />;
}