Dropdown Not Displayed in UI Dashboard, Only in Node-RED Editor

I’m creating a custom Node-RED node that includes a Vue.js-based dropdown using v-autocomplete. The goal is to display this dropdown in the Node-RED UI Dashboard. However, the dropdown appears only in the Node-RED editor and not in the actual dashboard.

Here’s a summary of my setup:

  1. The node’s HTML contains a <template> block for rendering the dropdown.
  2. The Vue.js script dynamically populates the dropdown options based on incoming messages (msg.payload).
  3. The Vue component renders correctly in the editor, but the dropdown is not visible in the dashboard.
<template>
  <div>
    <div class="msg">
      <v-form>
        <v-autocomplete
          :items="topologies.map(topology => topology.name)"
          label="Select Topology"
          placeholder="Search for the topologies"
          clearable
          chips
          variant="underlined"
          closable-chips
          v-model="selectedTopology">
        </v-autocomplete>
      </v-form>
      <div id="topology-container"></div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      topologies: [],
      selectedTopology: null,
    };
  },
  mounted() {
    this.$watch('msg.payload', (newPayload) => {
      if (Array.isArray(newPayload)) {
        this.topologies = newPayload;
      }
    });
  },
};
</script>

<style>
#topology-container {
  width: 100%;
  height: 100%;
}
</style>

  • How can I ensure the dropdown renders in the UI Dashboard rather than in the Node-RED editor?
  • Are there any specific considerations for embedding Vue.js components in the dashboard?
  • Do I need to modify the <template> block or use a different approach to integrate with the dashboard?

When you say it's rendering in the Node-RED Editor, can you screenshot this please?

I recommend forking GitHub - FlowFuse/node-red-dashboard-2-ui-example: An example project for writing third-party nodes that integrate with Node-RED Dashboard 2.0 in order to build your custom node as that already contains all of the templated code and folder structure you would need.

You can also read more about this in our documentation here

1 Like


but i need to bring that dropdown functionality through the dashboard ui. i created a new custom node red

For any pieces in the Node-RED Editor, you need to use jQuery or plain HTML/JS. The Vue components only work in the Dashboard itself, which you define in the .vue files (see the documentation and example I linked previously which covers this in more detail)

i followed the same example to understand and trying to create a new one with only one button. but i could get the proper output.

this is my ui-my-widget.html

<script type="text/javascript">
    RED.nodes.registerType("ui-my-widget", {
        category: "dashboard",
        color: "#f39c12",
        defaults: {
            name: { value: "" },
            group: { type: "ui_group" },
            order: { value: 0 },
            width: { value: 6 },
            height: { value: 1 },
        },
        icon: "dashboard.png",
        paletteLabel: "My Widget",
        label: function () {
            return this.name || "my widget";
        },
    });
</script>

<script type="text/html" data-template-name="ui-my-widget">
    <div class="form-row">
        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
        <input type="text" id="node-input-name" />
    </div>
</script>

<script type="text/html" data-help-name="ui-my-widget">
    <p>A custom widget for the Node-RED Dashboard 2.0.</p>
</script>

in my js file: ui-my-widget.js


module.exports = function (RED) {
    function UIMyWidgetNode(config) {
        RED.nodes.createNode(this, config);
        const node = this;

        // Get the group configuration
        const group = RED.nodes.getNode(config.group);

        // Register the widget with the Dashboard
        group.register(node, config, {
            events: {}, // Define events if needed
        });
    }

    // Register the node with Node-RED
    RED.nodes.registerType("ui-my-widget", UIMyWidgetNode);
};

my widget vue template: MyWidget.vue

<template>
    <div class="my-widget">
        <h3>{{ title }}</h3>
        <p>{{ description }}</p>
        <button @click="handleClick">Click Me</button>
    </div>
</template>

<script>
export default {
    props: {
        title: {
            type: String,
            default: "My Custom Widget",
        },
        description: {
            type: String,
            default: "This is a custom widget for Node-RED Dashboard.",
        },
    },
    methods: {
        handleClick() {
            console.log("Button clicked in the widget!");
        },
    },
};
</script>

<style>
.my-widget {
    border: 1px solid #ccc;
    padding: 10px;
    border-radius: 4px;
    text-align: center;
}
</style>

exported the vue components : ui/index.js

import MyWidget from "./components/MyWidget.vue";

export default {
    components: {
        MyWidget,
    },
};

Build Configuration (vite.config.js)

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

export default defineConfig({
    build: {
        lib: {
            entry: "./ui/index.js",
            name: "ui-my-widget",
            fileName: "ui-my-widget",
            formats: ["umd"],
        },
        rollupOptions: {
            output: {
                globals: {
                    vue: "Vue",
                },
            },
        },
    },
    plugins: [vue()],
});

package.json:

{
  "name": "red-dashboard-2-my-widget",
  "version": "1.0.0",
  "description": "",
  "main": "nodes/ui-my-widget.js",
  "scripts": {
    "build": "vite build",  
    "dev": "vite",             
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "dependencies": {
    "vue": "^3.2.0",
    "vite": "^4.0.0"
  },
    "devDependencies": {
      "@vitejs/plugin-vue": "^4.0.0"
  },
    "node-red": {
      "nodes": {
          "ui-my-widget": "nodes/ui-my-widget.js"
      }
  },
  "node-red-dashboard-2": {
      "widgets": {
          "ui-my-widget": {
              "output": "ui-my-widget.umd.js",
              "component": "MyWidget"
          }
      }
  },
  "author": "",
  "license": "ISC"
}

and my final output is like in the editor

why i m not able to see the button in the ui.

Assuming you are meaning the button you defined in the Vue html...

Where are you expecting to see the button ? In the node-red edit form?

no in the ui. i mean the dashboard

Have you added an instance of your node to the workspace and deployed it & refreshed the dashboard?

Actually. I just noticed you don't have any group specifier. What I mean by that is look at any of the built in nodes (like ui-text) - they all have a group selector so that the dashboard knows where to render the Vue to.

i did not get it . where i can modify my code.give me some information regarding that.

Look at the open and available source of any working dashboard 2 node and you will see where the group is defined in the html file.

E.g: node-red-dashboard/nodes/widgets/ui_button.html at 6e66c17846b26a37c6443550e51741b6825e9e1c · FlowFuse/node-red-dashboard · GitHub


Also, it's ui-group not ui_group

See node-red-dashboard/nodes/widgets/ui_button.html at 6e66c17846b26a37c6443550e51741b6825e9e1c · FlowFuse/node-red-dashboard · GitHub

now i changed my code by your guidance,still i did get the vue template button is not appearing in the dashboard. this is my code i changed and my configuration is given below:

<script type="text/javascript">
    RED.nodes.registerType("ui-my-widget", {
        category: "dashboard",
        color: "#f39c12",
        defaults: {
            name: { value: "" },
            group: { type: 'ui-group', required: true },
            order: { value: 0 },
            width: {
                    value: 0,
                    validate: function (v) {
                        const width = v || 0
                        const currentGroup = $('#node-input-group').val() || this.group
                        const groupNode = RED.nodes.node(currentGroup)
                        const valid = !groupNode || +width <= +groupNode.width
                        $('#node-input-size').toggleClass('input-error', !valid)
                        return valid
                    }
                },
            height: { value: 0 },
        },
        icon: "dashboard.png",
        paletteLabel: "My Widget",
        label: function () {
            return this.name || "my widget";
        },
        inputs: 1,
        outputs: 0,
        align: 'right',
        oneditprepare: function () {
                // if this groups parent is a subflow template, set the node-config-input-width and node-config-input-height up
                // as typedInputs and hide the elementSizer (as it doesn't make sense for subflow templates)
                if (RED.nodes.subflow(this.z)) {
                    // change inputs from hidden to text & display them
                    $('#node-input-width').attr('type', 'text')
                    $('#node-input-height').attr('type', 'text')
                    $('div.form-row.nr-db-ui-element-sizer-row').hide()
                    $('div.form-row.nr-db-ui-manual-size-row').show()
                } else {
                    // not in a subflow, use the elementSizer
                    $('div.form-row.nr-db-ui-element-sizer-row').show()
                    $('div.form-row.nr-db-ui-manual-size-row').hide()
                    $('#node-input-size').elementSizer({
                        width: '#node-input-width',
                        height: '#node-input-height',
                        group: '#node-input-group'
                    })
                }

                         
            }
    });
</script>

<script type="text/html" data-template-name="ui-my-widget">
    <div class="form-row">
        <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
        <input type="text" id="node-input-name" />
    </div>
    <div class="form-row">
        <label for="node-input-group"><i class="fa fa-table"></i> <span data-i18n="ui-text.label.group"></label>
        <input type="text" id="node-input-group">
    </div>
    <div class="form-row nr-db-ui-manual-size-row">
        <label><i class="fa fa-arrows-h"></i> <span data-i18n="ui-text.label.width">Width</label>
        <input type="hidden" id="node-input-width">
    </div>
    <div class="form-row nr-db-ui-manual-size-row">
        <label><i class="fa fa-arrows-v"></i> <span data-i18n="ui-text.label.height">Height</label>
        <input type="hidden" id="node-input-height">
    </div>
</script>

<script type="text/html" data-help-name="ui-my-widget">
    <p>A custom widget for the Node-RED Dashboard 2.0.</p>
</script>

configuration for the editor page : for group

in dashboard ui. i m getting the output as empty:


why i m not getting the vue button in the ui.