Form Builder
Metafox includes the most popular React Form library formik and validation with yup, wraps theme in FormBuilder in order to help build, configure flexible logic from AdminCP without modifying source code.
The Form mechanism on MetaFox is based on formik + material-ui. It can build a Form with certain fields & structure with JSON schema. Let's take a look at the below example.
Schema
import { Form } from "@metafox/form";
const ExampleLoginForm = () => {
const loginFormSchema = {
{
"component": "Form",
"method": "POST",
"title": "Login",
"noBreadcrumb": true,
"submitAction": "@login",
"action": "/user/login",
"acceptPageParams": [
"returnUrl"
],
"value": [],
"validation": {
"type": "object",
"properties": {
"email": {
"type": "string",
"errors": {
"required": "[${path} is a required field.]"
},
"required": true,
"label": "[Username, email or phone number]"
},
"password": {
"type": "string",
"errors": {
"required": "[${path} is a required field.]"
},
"required": true,
"label": "[Password]"
}
}
},
"elements": {
"basic": {
"component": "Container",
"name": "basic",
"testid": "field basic",
"elements": {
"email": {
"name": "email",
"maxLength": 255,
"fullWidth": true,
"variant": "outlined",
"margin": "normal",
"size": "medium",
"component": "Text",
"label": "[Username, email or phone number]",
"required": true,
"inputLabelProps": {
"shrink": true
},
"placeholder": "[Enter your username, email or phone number]",
"autoComplete": "email",
"autoFocus": true,
"testid": "field email"
},
"password": {
"component": "Password",
"name": "password",
"type": "password",
"autoComplete": "password",
"maxLength": 255,
"fullWidth": true,
"variant": "outlined",
"label": "[Password]",
"required": true,
"margin": "normal",
"inputLabelProps": {
"shrink": true
},
"placeholder": "[Enter your password]",
"testid": "field password"
},
"remember": {
"component": "Checkbox",
"checkedValue": true,
"uncheckedValue": 0,
"fullWidth": true,
"margin": "dense",
"name": "remember",
"label": "[Remember Me]",
"testid": "field remember"
},
"login": {
"component": "Submit",
"name": "login",
"size": "large",
"variant": "contained",
"label": "[Sign In]",
"type": "submit",
"color": "primary",
"margin": "normal",
"fullWidth": true,
"testid": "field login"
},
"forgotPassword": {
"component": "LinkButton",
"color": "primary",
"variant": "link",
"size": "medium",
"fullWidth": true,
"name": "forgotPassword",
"link": "/user/password/request",
"margin": "none",
"label": "[Forgot Password?]",
"testid": "field forgotPassword"
},
"register": {
"component": "LinkButton",
"color": "primary",
"variant": "outlined",
"size": "large",
"fullWidth": true,
"name": "register",
"link": "/register",
"margin": "dense",
"label": "[Don't have an account?]",
"sx": {
"pt": 3
},
"testid": "field register"
},
"returnUrl": {
"component": "Hidden",
"name": "returnUrl",
"testid": "field returnUrl"
}
}
}
}
}
};
const initialValues = {
email: "[email protected]",
password: "",
};
return <Form schema={loginFormSchema} initialValues={initialValues} />;
};Elements
Here is the list of Supported Form elements
Text
Definition
export type TextFieldProps = {
name: string;
component: "Text";
label: string;
placeholder: string;
readOnly?: boolean;
disabled?: boolean;
required?: boolean;
maxLength?: number;
variant?: "outlined" | "filled";
type?: "text" | "email" | "password" | "number" | "date" | "time";
};Blow is the example to create a Text element
const Field = {
name: "title",
component: "Text",
label: "Title",
placeholder: "Enter an title for this blog",
readOnly: false, // optional
disabled: false, // optional
required: false, // optional
maxLength: 250, // optional
autoComplete: true, //optional,
variant: "outlined",
};Switch
Definition:
export type SwitchFieldProps = {
name: string;
component: "Switch";
label: string;
placeholder: string;
readOnly?: boolean;
disabled?: boolean;
required?: boolean;
maxLength?: number;
variant?: "outlined" | "filled";
type?: "text" | "email" | "password" | "number" | "date" | "time";
label: string;
margin: "dense" | "none" | "normal";
labelPlacement?: "bottom" | "end" | "start" | "top";
checkedValue?: any;
uncheckedValue?: any;
size: "medium" | "small" | string;
color:
| "default"
| "primary"
| "secondary"
| "error"
| "info"
| "success"
| "warning"
| string;
fullWidth: boolean;
warning?: string;
description?: string;
variant: "filled" | "outlined" | "standard";
};Example:
const Field = {
component: "Switch",
fullWidth: true,
margin: "normal",
color: "primary",
labelPlacement: "start",
name: "is_wiki",
label: "Label here ...",
description: "Description here ...",
testid: "field toggle",
};Checkbox
Definition:
export type SwitchFieldProps = {
name: string;
component: "Checkbox";
variant: "filled" | "outlined" | "standard";
label: string;
disabled?: boolean;
checkedValue?: any;
uncheckedValue?: any;
margin: "dense" | "none" | "normal";
size: "medium" | "small" | string;
fullWidth: boolean;
color:
| "default"
| "primary"
| "secondary"
| "error"
| "info"
| "success"
| "warning"
| string;
description?: string;
required?: boolean;
sxFieldWrapper?: sxMui;
};Example:
const Field = {
component: "Checkbox",
checkedValue: 1,
uncheckedValue: 0,
fullWidth: true,
margin: "dense",
name: "is_active",
multiple: false,
label: "Label here ...",
disabled: false,
testid: "field is_active",
};RadioGroup
Definition:
export type SwitchFieldProps = {
name: string;
component: "RadioGroup";
variant: "filled" | "outlined" | "standard";
label: string;
disabled?: boolean;
margin: "dense" | "none" | "normal";
size: "medium" | "small" | string;
fullWidth: boolean;
description?: string;
required?: boolean;
};Example:
const Field = {
component: "RadioGroup",
options: [
{
label: "Option 1",
value: 1,
},
{
label: "Option 2",
value: 2,
},
],
fullWidth: true,
name: "field_radio",
label: "Label",
description: "Description here ...",
required: false,
descriptionPlacement: "bottom",
testid: "field field_radio",
};Select
Definition:
export type SwitchFieldProps = {
name: string;
component: "RadioGroup";
variant: "filled" | "outlined" | "standard";
label: string;
disabled?: boolean;
margin: "dense" | "none" | "normal";
size: "medium" | "small" | string;
fullWidth: boolean;
description?: string;
required?: boolean;
sxFieldWrapper?: sxMui;
options: Array[];
};Example:
const Field = {
component: "Select",
fullWidth: true,
name: "field_select",
label: "selection",
description: "Description here ...",
required: false,
options: [
{
label: "Option 1",
value: 1,
},
{
label: "Option 2",
value: 2,
},
],
testid: "field field_select",
};Datetime
Definition:
export type SwitchFieldProps = {
name: string;
component: "Datetime";
variant: "filled" | "outlined" | "standard";
label: string;
disabled?: boolean;
margin: "dense" | "none" | "normal";
size: "medium" | "small" | string;
fullWidth: boolean;
description?: string;
required?: boolean;
displayFormat: string;
timeFormat: 12 | 24;
timeSuggestion: boolean;
labelTimePicker: string;
labelDatePicker: string;
};Example:
const Field = {
component: "Datetime",
variant: "outlined",
name: "start_time",
required: true,
disabled: false,
displayFormat: "DD/MM/YYYY - HH:mm",
timeFormat: 24,
timeSuggestion: true,
labelTimePicker: "Start Time",
labelDatePicker: "Start Date",
testid: "field start_time",
};Tags
Definition:
export type SwitchFieldProps = {
name: string;
component: "Tags";
variant: "filled" | "outlined" | "standard";
label: string;
disabled?: boolean;
margin: "dense" | "none" | "normal";
size: "medium" | "small" | string;
fullWidth: boolean;
description?: string;
required?: boolean;
search_endpoint: string;
placeholder?: string;
};Example:
const Field = {
component: "Tags",
maxLength: 255,
name: "tags",
fullWidth: true,
margin: "normal",
variant: "outlined",
search_endpoint: "/hashtag/suggestion",
description: "Separate multiple topics by entering.",
label: "Topics",
placeholder: "Keywords",
testid: "field tags",
};PrivacySelect
Definition:
export type SwitchFieldProps = {
name: string;
component: "Privacy";
variant: "filled" | "outlined" | "standard";
label: string;
disabled?: boolean;
margin: "dense" | "none" | "normal";
fullWidth: boolean;
description?: string;
required?: boolean;
options: Array[];
};Example:
const Field = {
"component": "Privacy",
"label": "Privacy",
"name": "privacy",
"fullWidth": true,
"variant": "outlined",
"options": [
{
"label": "Everyone",
"value": 0
},
{
"label": "Community",
"value": 1
},
{
"label": "Friends",
"value": 2
},
{
"label": "Friends of Friends",
"value": 3
},
{
"label": "Only Me",
"value": 4
},
{
"label": "Custom",
"value": 10
}
],
"description": "Control who can see this blog.",
"testid": "field privacy"
};ButtonSubmit
Definition:
export type SwitchFieldProps = {
name: string;
component: "Submit";
type: 'button';
disabled: boolean;
color:
| "default"
| "primary"
| "secondary"
| "error"
| "info"
| "success"
| "warning"
| string;
margin: "dense" | "none" | "normal";
label: string;
size: "large" | "medium" | "small" | string;
fullWidth: boolean;
variant: "outlined" | "contained" | "text"
};Example:
const Field = {
"component": "Submit",
"name": "submit",
"size": "large",
"variant": "contained",
"label": "Update",
"type": "submit",
"color": "primary",
"testid": "field submit"
};Button
Definition:
export type SwitchFieldProps = {
name: string;
component: "Button";
type: 'button';
disabled: boolean;
color:
| "default"
| "primary"
| "secondary"
| "error"
| "info"
| "success"
| "warning"
| string;
margin: "dense" | "none" | "normal";
label: string;
size: "large" | "medium" | "small" | string;
fullWidth: boolean;
variant: "outlined" | "contained" | "text"
};Example:
const Field = {
"component": "Button",
"name": "action",
"size": "large",
"variant": "contained",
"label": "Update",
"type": "button",
"color": "primary",
"testid": "field action"
};Container
Definition:
export type SwitchFieldProps = {
name: string;
component: "Container";
elements: Record<string, FormElementShape>;
collapsible?: boolean;
variant: "vertical" | "horizontal";
label: string;
wrapperProps?: Record<string, any>;
};Example:
const Field = {
"component": "Container",
"name": "customsection",
"label": "Container",
"description": null,
"testid": "field customsection",
"elements": {
// config elements
}
}Note: During Metafox upgrade, config may be unwanted change that this document can be outdated. Please refer to the source code during develop to update the latest fields config.