Frontend
Form Builder

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.