diff --git a/ui/src/components/PluginRender/index.tsx b/ui/src/components/PluginRender/index.tsx
index ff68f567..3ed8a20d 100644
--- a/ui/src/components/PluginRender/index.tsx
+++ b/ui/src/components/PluginRender/index.tsx
@@ -1,35 +1,52 @@
-import { FC, ReactNode } from 'react';
+import { FC, ReactNode, memo } from 'react';
 
 import builtin from '@/plugins/builtin';
 import * as plugins from '@/plugins';
-import { Plugin } from '@/utils/pluginKit';
+import { Plugin, PluginType } from '@/utils/pluginKit';
+
+/**
+ * Noteļ¼šPlease set at least either of the `slug_name` and `type` attributes, otherwise no plugins will be rendered.
+ *
+ * @field slug_name: The `slug_name` of the plugin needs to be rendered.
+ *                   If this property is set, `PluginRender` will use it first (regardless of whether `type` is set)
+ *                   to find the corresponding plugin and render it.
+ * @field type: Used to formulate the rendering of all plugins of this type.
+ *              (if the `slug_name` attribute is set, it will be ignored)
+ * @field prop: Any attribute you want to configure, e.g. `className`
+ */
 
 interface Props {
-  slug_name: string;
+  slug_name?: string;
+  type?: PluginType;
   children?: ReactNode;
   [prop: string]: any;
 }
 
-const findPluginBySlugName: (l, n) => Plugin | null = (source, slug_name) => {
-  let ret: Plugin | null = null;
+const findPlugin: (s, k: 'slug_name' | 'type', v) => Plugin[] = (
+  source,
+  k,
+  v,
+) => {
+  const ret: Plugin[] = [];
   if (source) {
-    Object.keys(source).forEach((k) => {
-      const p = source[k];
-      if (p && p.info && p.info.slug_name === slug_name && p.component) {
-        ret = p;
+    Object.keys(source).forEach((i) => {
+      const p = source[i];
+      if (p && p.component && p.info && p.info[k] === v) {
+        ret.push(p);
       }
     });
   }
-
   return ret;
 };
 
-const Index: FC<Props> = ({ slug_name, children, ...props }) => {
-  const bp = findPluginBySlugName(builtin, slug_name);
-  const vp = findPluginBySlugName(plugins, slug_name);
-  const plugin = bp || vp;
+const Index: FC<Props> = ({ slug_name, type, children, ...props }) => {
+  const fk = slug_name ? 'slug_name' : 'type';
+  const fv = fk === 'slug_name' ? slug_name : type;
+  const bp = findPlugin(builtin, fk, fv);
+  const vp = findPlugin(plugins, fk, fv);
+  const pluginSlice = [...bp, ...vp];
 
-  if (!plugin) {
+  if (!pluginSlice.length) {
     return null;
   }
   /**
@@ -37,9 +54,19 @@ const Index: FC<Props> = ({ slug_name, children, ...props }) => {
    * ps: Logic such as version compatibility determination can be placed here
    */
 
-  const PluginComponent = plugin.component;
-  // @ts-ignore
-  return <PluginComponent {...props}>{children}</PluginComponent>;
+  return (
+    <>
+      {pluginSlice.map((ps) => {
+        const PluginFC = ps.component;
+        return (
+          // @ts-ignore
+          <PluginFC key={ps.info.slug_name} {...props}>
+            {children}
+          </PluginFC>
+        );
+      })}
+    </>
+  );
 };
 
-export default Index;
+export default memo(Index);
diff --git a/ui/src/pages/Users/Login/index.tsx b/ui/src/pages/Users/Login/index.tsx
index 7bb293fb..a6bedd59 100644
--- a/ui/src/pages/Users/Login/index.tsx
+++ b/ui/src/pages/Users/Login/index.tsx
@@ -175,15 +175,12 @@ const Index: React.FC = () => {
   return (
     <Container style={{ paddingTop: '4rem', paddingBottom: '5rem' }}>
       <WelcomeTitle />
-      <Col className="mx-auto" md={6} lg={4} xl={3}>
-        <PluginRender slug_name="ui_plugin_demo" className="mb-5" />
-      </Col>
       {step === 1 ? (
         <Col className="mx-auto" md={6} lg={4} xl={3}>
           {ucAgentInfo ? (
             <PluginRender slug_name="uc_login" className="mb-5" />
           ) : (
-            <PluginRender slug_name="connector" className="mb-5" />
+            <PluginRender type="Connector" className="mb-5" />
           )}
           {canOriginalLogin ? (
             <>
diff --git a/ui/src/pages/Users/Register/index.tsx b/ui/src/pages/Users/Register/index.tsx
index 712485ef..efc10351 100644
--- a/ui/src/pages/Users/Register/index.tsx
+++ b/ui/src/pages/Users/Register/index.tsx
@@ -26,7 +26,7 @@ const Index: React.FC = () => {
 
       {showForm ? (
         <Col className="mx-auto" md={6} lg={4} xl={3}>
-          <PluginRender slug_name="connector" className="mb-5" />
+          <PluginRender type="Connector" className="mb-5" />
           <SignUpForm callback={onStep} />
         </Col>
       ) : (
diff --git a/ui/src/plugins/Demo/demo.go b/ui/src/plugins/Demo/demo.go
new file mode 100644
index 00000000..2f1795f1
--- /dev/null
+++ b/ui/src/plugins/Demo/demo.go
@@ -0,0 +1,20 @@
+package demo
+
+import "github.com/answerdev/answer/plugin"
+
+type DemoPlugin struct {
+}
+
+func init() {
+	plugin.Register(&DemoPlugin{})
+}
+
+func (d DemoPlugin) Info() plugin.Info {
+	return plugin.Info{
+		Name:        plugin.MakeTranslator("i18n.demo.name"),
+		SlugName:    "demo_plugin",
+		Description: plugin.MakeTranslator("i18n.demo.description"),
+		Author:      "answerdev",
+		Version:     "0.0.1",
+	}
+}
diff --git a/ui/src/plugins/builtin/Connector/index.tsx b/ui/src/plugins/builtin/Connector/index.tsx
index d07624e8..c5b39431 100644
--- a/ui/src/plugins/builtin/Connector/index.tsx
+++ b/ui/src/plugins/builtin/Connector/index.tsx
@@ -13,6 +13,7 @@ import './i18n';
 
 const pluginInfo: PluginInfo = {
   slug_name: info.slug_name,
+  type: info.type,
 };
 interface Props {
   className?: string;
diff --git a/ui/src/plugins/builtin/Connector/info.yaml b/ui/src/plugins/builtin/Connector/info.yaml
index ba65c13e..7155daec 100644
--- a/ui/src/plugins/builtin/Connector/info.yaml
+++ b/ui/src/plugins/builtin/Connector/info.yaml
@@ -1,4 +1,5 @@
 slug_name: connector
+type: Connector
 version: 0.0.1
 link: https://github.com/answerdev/plugins/tree/main/connector/
 author:  Answer.dev
diff --git a/ui/src/plugins/index.ts b/ui/src/plugins/index.ts
index 6a551eaf..bb6104ab 100644
--- a/ui/src/plugins/index.ts
+++ b/ui/src/plugins/index.ts
@@ -1,3 +1,3 @@
 export default null;
 
-export { default as Demo } from './Demo';
+// export { default as Demo } from './Demo';
diff --git a/ui/src/utils/pluginKit.ts b/ui/src/utils/pluginKit.ts
index f65d3bf1..3b88b582 100644
--- a/ui/src/utils/pluginKit.ts
+++ b/ui/src/utils/pluginKit.ts
@@ -7,14 +7,19 @@ import i18next from 'i18next';
  * It may be used for feature upgrades or version compatibility processing.
  *
  * @field slug_name: Unique identity string for the plugin, usually configured in `info.yaml`
+ * @field type: The type of plugin is defined and a single type of plugin can have multiple implementations.
+ *              For example, a plugin of type `Connector` can have a `google` implementation and a `github` implementation.
+ *              `PluginRender` automatically renders the plug-in types already included in `PluginType`.
  * @field name: Plugin name, optionally configurable. Usually read from the `i18n` file
  * @field description: Plugin description, optionally configurable. Usually read from the `i18n` file
  */
 
 const I18N_NS = 'plugin';
 
+export type PluginType = 'Connector';
 export interface PluginInfo {
   slug_name: string;
+  type?: PluginType;
   name?: string;
   description?: string;
 }