Skip to content

Extend Component ​

Integrate custom components into the designer to extend functionality. This guide shows how to create and use custom components.

View built-in form components and configurable parameters in the Renderer Documentation.

See Custom Form Components for development specifications and requirements.

View more component drag configuration rules in the Source Code.

Note

Global drag rule registration is supported through FcDesigner.addDragRule, enabling one-time configuration for use in multiple places. Method Documentation

Extend Component Tutorial ​

Step-by-step guide to creating a Title component that displays various title texts in forms.

component1

1. Package Component ​

Create a new Title.vue file with component functionality and styles:

vue
<template>
    <div class="_fc-title" :class="size || 'h2'" :style="textStyle">
        {{ title }}
    </div>
</template>
<script>
    import {defineComponent} from 'vue';
    export default defineComponent({
        name: 'FcTitle',
        data() {
            return {};
        },
        props: {
            title: String,
            size: String,
            align: String,
        },
        computed: {
            textStyle() {
                return {
                    textAlign: this.align || 'left',
                }
            }
        }
    });
</script>
<style>
    ._fc-title {
        width: 100%;
        font-size: 16px;
        font-weight: 600;
        margin-top: 1em;
        margin-bottom: 16px;
    }

    ._fc-title.h1, ._fc-title.h2 {
        padding-bottom: .3em;
        border-bottom: 1px solid #eee
    }

    ._fc-title.h1 {
        font-size: 32px;
        line-height: 1.2
    }

    ._fc-title.h2 {
        font-size: 24px;
        line-height: 1.225
    }

    ._fc-title.h3 {
        font-size: 20px;
        line-height: 1.43
    }

    ._fc-title.h4 {
        font-size: 16px;
    }

    ._fc-title.h5 {
        font-size: 14px;
    }

    ._fc-title.h6 {
        font-size: 12px;
    }
</style>

2. Mount Component ​

Mount the Title component in main.js

ts
import Title from 'Title.vue'
import FcDesigner from '@form-create/designer'

FcDesigner.component('Title', Title);
// Or mount globally through app
app.component('Title', Title);

Or mount the Title component in a component

vue
<script>
    import {defineComponent} from 'vue'; 
    import Title from 'Title.vue';
    import FcDesigner from '@form-create/designer'
    export default defineComponent({
        mounted() {
            FcDesigner.component('Title', Title);
        }
    });
</script>

3. Define Drag Rule ​

Define the drag rule for the Title component

js
const titleDragRule = {
    menu: 'aide',
    icon: 'icon-title',
    label: 'Title',
    // Unique ID
    name: 'title',
    // Events that can be configured for the component
    event: ['click'],
    rule() {
        // Component rendering rule
        return {
            // Component name, corresponding to the previous step
            type: 'Title',
            props: {
                title: 'Custom Title',
            },
        };
    },
    props() {
        // Configuration items on the right side of the component, corresponding to props in the component
        return [
            {type: 'input', field: 'title', title: 'Title'},
            {
                type: 'select',
                field: 'size',
                title: 'Size',
                // Default value
                value: 'H2',
                options: [1, 2, 3, 4, 5, 6].map(k => {
                    return {label: 'H' + k, value: 'h' + k};
                })
            }, {
                type: 'select',
                field: 'align',
                title: 'Position',
                options: [
                    {label: 'Left', value: 'left'},
                    {label: 'Center', value: 'center'},
                    {label: 'Right', value: 'right'}
                ]
        }];
    }
};

View built-in form components and configurable parameters in the Renderer Documentation.

component2

The configuration panel on the right is automatically generated based on the rules defined in the props function.

4. Import Drag Rule ​

Mount the drag rule to the designer:

js
// Assume this is your Vue component
export default {
    mounted() {
        // Mount drag rule
        this.$refs.designer.addComponent(titleDragRule);
    }
};

These steps let you integrate custom components with the designer and define their drag behavior and property configurations.

Extend Form Component Tutorial ​

Custom form components implement business-specific form controls. This section covers how to define and use them, including importing, mounting, and setting drag rules.

See Custom Form Components for development specifications and requirements.

1. Package Component ​

Step-by-step guide to developing a custom input component based on Element Plus Input.

Create a new Input.vue file:

vue
<template>
    <el-input :disabled="disabled" :modelValue="modelValue" @update:modelValue="handleChange" v-bind="$attrs">
        <!-- Custom component slot -->
        <template #prepend>Http://</template>
    </el-input>
</template>
<script>
    import {defineComponent} from 'vue';
    export default defineComponent({
        name: 'FcInput',
        data() {
            return {};
        },
        emits: ['update:modelValue', 'change'],
        props: {
            // Get form data
            modelValue: String,
            // Support form disabled functionality
            disabled: Boolean
        },
        methods: {
            // Update form data
            handleChange(val) {
                this.$emit('update:modelValue', val);
                // Trigger change event
                this.$emit('change', val);
            }
        }
    });
</script>

Using v-bind="$attrs" automatically passes all configuration items to el-input, inheriting all properties without redefining them.

2. Mount Component ​

Mount the Input component in main.js

ts
import Input from 'Input.vue'
import FcDesigner from '@form-create/designer'

FcDesigner.component('FcInput', Input);
// Or mount globally through app
app.component('FcInput', Input);

Or mount the Input component in a component

vue
<script>
    import {defineComponent} from 'vue'; 
    import Input from 'Input.vue';
    import FcDesigner from '@form-create/designer'
    export default defineComponent({
        mounted() {
            FcDesigner.component('FcInput', Input);
        }
    });
</script>

3. Define Drag Rule ​

Define the drag rule for the Input component

ts
import uniqueId from '@form-create/utils/lib/unique';
const InputDragRule = {
    menu: 'main',
    icon: 'icon-input',
    label: 'Custom Input',
    // Unique ID
    name: 'FcInput',
    // Form component identifier
    input: true,
    // Component events
    event: ['blur', 'focus', 'change', 'input', 'clear'],
    validate: ['string', 'url', 'email'],
    rule({t}) {
        return {
            // Component name, corresponding to the previous step
            type: 'FcInput',
            field: uniqueId(),
            title: 'Custom Input',
            info: '',
            $required: false,
            props: {}
        };
    },
    props() {
        return [
            {
                type: 'switch',
                title: 'Disabled',
                field: 'disabled'
            },
            {
                type: 'switch',
                title: 'Clearable',
                field: 'clearable'
            },
            {
                type: 'input',
                title: 'Placeholder',
                field: 'placeholder'
            },
        ];
    }
};
export default InputDragRule;

View built-in form components and configurable parameters in the Renderer Documentation.

Note: To use uniqueId, install the @form-create/utils package, or implement custom logic to generate unique IDs starting with a letter (no symbols allowed).

sh
npm install @form-create/utils@^3

4. Import Drag Rule ​

Mount the drag rule to the designer:

js
// Assume this is your Vue component
export default {
    mounted() {
        // Mount drag rule
        this.$refs.designer.addComponent(InputDragRule);
    }
};

props Configuration Name Mapping Rules ​

If field starts with formCreate in the component configuration rule (props) method, the system automatically maps it to the corresponding field in the rule.

FieldDescription
typeModifies the rule.props.type field
options>labelModifies the rule.props.options.label field
formCreateStyleModifies the rule.style field
formCreateStyle>widthModifies the rule.style.width field
formCreateChildModifies rule.children[0]

For example:

js
{
    props() {
        return [
            {
                type: 'switch',
                title: 'Disabled',
                // Configuration name, modifies rule.props.disabled
                field: 'disabled'
            },
            {
                type: 'switch',
                title: 'Clearable',
                // Configuration name, modifies rule.props.clearable
                field: 'clearable'
            },
            {
                type: 'input',
                title: 'Placeholder',
                // Configuration name, modifies rule.props.placeholder
                field: 'placeholder'
            },
        ];
    }
}

More Examples ​

Restrict to Only One Drag-in ​

ts
const InputDragRule = {
    menu: 'main',
    icon: 'icon-input',
    label: 'Custom Input',
    name: 'FcInput',
    // Only one can be dragged in
    only: true,
    //...
}

Restrict to Only Drag into Group Component ​

ts
const InputDragRule = {
    menu: 'main',
    icon: 'icon-input',
    label: 'Custom Input',
    name: 'FcInput',
    // Restrict to only drag into group component
    allowDragTo: ['group'],
    //...
}

Inline Component ​

Inline components don't automatically expand to 100% width:

ts
const InputDragRule = {
    menu: 'main',
    icon: 'icon-input',
    label: 'Custom Input',
    name: 'FcInput',
    // Inline component identifier
    inline: true,
    //...
}

Define Multi-language IDs Needed by Component ​

ts
const InputDragRule = {
    menu: 'subform',
    icon: 'icon-table-form',
    label: 'Table Form',
    name: 'tableForm',
    input: true,
    mask: false,
    subForm: 'array',
    // Multi-language ID
    languageKey: ['add', 'operation', 'dataEmpty'],
    //...
}

Disable Component Style Configuration ​

ts
const InputDragRule = {
    menu: 'main',
    icon: 'icon-input',
    label: 'Custom Input',
    name: 'FcInput',
    // Disable component style configuration
    style: false,
    //...
}

Transform Component Rule ​

For example, the sub-form rules of the group component are actually stored in props.rule, but are displayed in the children field for visual design convenience. In this case, bidirectional data transformation adaptation is needed.

ts
const InputDragRule = {
    menu: 'main',
    icon: 'icon-input',
    label: 'Custom Input',
    name: 'FcInput',
    // When loading designer rendering rules
    loadRule(rule) {
        rule.children = rule.props.rule || [];
        rule.type = 'FcRow';
        delete rule.props.rule;
    },
    // Triggered when exporting final rendering rules
    parseRule(rule) {
        rule.props.rule = rule.children;
        rule.type = 'group';
        delete rule.children;
        delete rule.props.mode;
    },
    //...
}

Data Structure ​

ts
interface DragRule {
    // Component ID, must be unique
    name: string;
    // Component name
    label: string;
    // Component icon
    icon: string;
    // Insertion category
    menu?: MenuName;
    // Whether style configuration is supported
    style?: boolean;
    // Whether it's an inline component
    inline?: boolean;
    // Whether it's a form component
    input?: boolean;
    // Control maximum number of child components that can be dragged in
    maxChildren?: number;
    // If it's a sub-form component, need to define the type of `value`
    subForm?: 'object' | 'array';
    // List of draggable components (available for container components)
    allowDrag?: AllowDrag;
    // List of non-draggable components (available for container components)
    denyDrag?: DenyDrag;
    // Components into which this component can be dragged
    allowDragTo?: string | string[];
    // Component, not recommended
    component?: Component;
    // List of rendered child components
    subRender: ({h, resolveComponent, subRule, rule}: {
        h: typeof H<any>,
        resolveComponent: typeof ResolveComponent,
        subRule: Rule,
        rule: Rule
    }) => Array<{
        label: string;
        vnode: VNode
    }>;
    // Configure component condition selection method
    condition: conditionComponentType | ((rule: Rule) => ({
        // Component type
        type: conditionComponentType;
        // Selection options
        options?: any[];
        // Component type
        props?: Object;
    }));
    // Multi-language configuration items
    languageKey: string[];
    // Form global configuration
    formOptions?: {
        globalClass?: GlobalClass;
        globalVariable?: GlobalVariable;
        globalData?: GlobalData;
        globalEvent?: GlobalEvent;
        language?: Object;
        style?: string;
    } | string;
    // Component generation rule
    rule(arg: { t: t }): Rule;
    // Component property configuration rule
    props(rule: Rule, arg: { t: t, api: Api }): Rule[];
    // Convert to final rule when exporting rules through this method
    parseRule?: (rule: Rule) => void;
    // Convert to designer rendering rule when importing rules through this method
    loadRule?: (rule: Rule) => void;
    // Triggered when fields in props change
    watch?: {
        [key: string]: (arg: { value: any, rule: Rule, api: Api, field: string }) => void;
    };
    // Whether there are matching child components, e.g., Row and Col
    children?: string;
    // Number of child components to render during initialization
    childrenLen?: number;
    // Whether the current component's operation container is displayed inside the component. When false, the operation container wraps the current component
    inside?: true | boolean;
    // Whether other components can be dragged into the current component
    drag?: true | string | boolean;
    // Whether to display drag button
    dragBtn?: false | boolean;
    // Control whether operation buttons are displayed and which ones
    handleBtn?: true | boolean | Array<'create' | 'copy' | 'addChild' | 'delete'>;
    // Hide fields in basic configuration
    hiddenBaseField?: string[];
    // Whether to display mask to avoid component operations. Recommended true when there are child components, false otherwise
    mask?: false | boolean;
    // Whether only one can be dragged in
    only?: boolean;
    // Whether to generate name
    aide?: boolean;
    // Current component's slots
    easySlots?: Array<string| {
        // Slot name
        value: string;
        // Slot description
        label?: string;
        // Type
        type?: 'icon' | 'text'
    }>;
    // Events supported by current component
    event?: string[];
    // Data type of current component's `value`. When 'required', only display whether it's required
    validate?: string[] | 'required' | boolean;
}