# Tutorial - create a sidebar plugin and persist the data in a config node

**URL:** <https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020>\
**Category:** Developing Nodes\
**Created:** [14 October 2023 07:24 UTC](https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020 "2023-10-14T07:24:22Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [14 October 2023 07:24 UTC](https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020/1 "2023-10-14T07:24:22Z")

</div>

Hi folks,

Developing nodes for Node-RED is not difficult, once you know how to do it. However I always forget how to create a sidebar plugin, to show a panel in the right sidebar of the flow editor. Especially if the user needs to enter data in the sidebar, and you want to remember that data. So I decided to explain here how I do it. I have only developed a couple of sidebar plugins, so I am by far a specialist. So others may have better ways to do it...

So hopefully other developers can benefit from it. Hint for a.o. @gregorius 😇

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/7/0/70a7e7549353165fb3752cf16095150a9f860e61.png)

The development steps in detail:

1. Start by telling Node-RED that - at startup time - the backend needs to load your config node js file, and the flow editor frontend needs to load your plugin html file. Do this by adding this snippet into your `package.json` file:

2. Add a normal config node js file to your project, which most of the time does only register itself into the Node-RED runtime:

3. Add a normal config node html file (for the same config node name), where you add an html element for all the data that your want to persist:

4. The html file for the sidebar plugin looks like this:

5. And finally you need to implement the `ensureYourConfigNodeExists()` function. The following implementation does the job well for me:

Good luck with the development of your first sidebar (accompanied by a config node)!

Bart

---

<div class="post-metadata">

**Author:** ![kuema](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/kuema/32/6542_2.png) [@kuema](https://discourse.nodered.org/u/kuema)\
**Post date:** [14 October 2023 08:06 UTC](https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020/2 "2023-10-14T08:06:51Z")

</div>

Nice tutorial, thank you Bart! 🤓

I wonder if stuff like that could make it into the [tutorials section](https://nodered.org/docs/tutorials/) of the official documentation? 🤔

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [14 October 2023 08:31 UTC](https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020/3 "2023-10-14T08:31:00Z")

</div>

Hi @kuema,  
That is indeed an idea. But in fact writing this one here (without restrictions about styling, and so on...) was already a bit too much for my free time restrictions. I hadn't even the time to test this (simplified) code examples. So unfortunately this is by far the most I can offer ar the moment. It is this or nothing 🙄

---

<div class="post-metadata">

**Author:** ![gregorius](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/gregorius/32/73816_2.png) [@gregorius](https://discourse.nodered.org/u/gregorius)\
**Post date:** [14 October 2023 09:18 UTC](https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020/4 "2023-10-14T09:18:11Z")

</div>

Thank you for the explanation, I will brazenly copy it 🙂

> [@BartButenaers](#):
>
> ```auto
> if (globalYourConfigNode.someData] != data) {
> globalYourConfigNode.someData] != data;
> // Since the config node has been updated, the 'Deploy' button should become active
> RED.nodes.dirty(true);
> }
> 
> ```

is the second line actually `globalYourConfigNode.someData = data;`

> [@BartButenaers](#):
>
> The `hasUsers` needs to be false

Does that ensure the node _isn't_ shown in the palette sidebar? If I understand the tutorial correctly the node is shown but can't be edited - so question becomes, why would it be shown in the first place?

To avoid confusion, this is what I mean as palette sidebar:

 ![Screen Shot 2023-10-14 at 11.17.00](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/2/d/2d6e75724bbd92527665a69a8d6426617d5c6484.png)

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [14 October 2023 11:04 UTC](https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020/5 "2023-10-14T11:04:43Z")

</div>

> [@BartButenaers](#):
>
> But in fact writing this one here (without restrictions about styling, and so on...) was already a bit too much for my free time restrictions.

I've hit this problem myself a number of times.

It would be really nice to have some process that let people submit documentation improvements/corrections in a way that could be properly incorporated when someone actually gets time to download the doc repo, works out what/where to update, sorts out the style and submit a PR.

I suspect that would let the Node-RED documentation improve at a higher pace.

---

<div class="post-metadata">

**Author:** ![ralphwetzel](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/ralphwetzel/32/53713_2.png) [@ralphwetzel](https://discourse.nodered.org/u/ralphwetzel)\
**Post date:** [14 October 2023 12:38 UTC](https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020/6 "2023-10-14T12:38:51Z")

</div>

> [@gregorius](#):
>
> Does that ensure the node _isn't_ shown in the palette sidebar? If I understand the tutorial correctly the node is shown but can't be edited - so question becomes, why would it be shown in the first place?

As it's a node registered with category defined `config`, it won't show up in the (left-hand) palette sidebar.

Once created, it will yet show up in the (right-hand) `Configuration nodes` panel - similar to the `global-config` config node that is used to store the global env variable data (NR v3.1).

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/0/3/03aae32de4a5b7add15c0d1b3d09b4f3b2bb5abd.png)

That said, I think (yet haven't tested) it's not necessary to create html elements for the stored data (and then disable those); it should be enough to declare the `defaults`.

@BartButenaers: Great idea to put this knowledge into a tutorial!

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [14 October 2023 15:31 UTC](https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020/7 "2023-10-14T15:31:47Z")

</div>

@gregorius as @ralphwetzel explains, the config node will show up in the config nodes list. So not in the palette, because you don't add a config node manually in your flow. Instead config nodes are being created automatically by other nodes, when the user creates another [configuration](https://nodered.org/docs/creating-nodes/config-nodes) for that node.

That is why I explained that ´hasUsers´ needs to be set to false. Because our config node is not linked to another node, so it would end up incorrectly between the unused config nodes:

 ![Screenshot_20231014-171703_Chrome](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/d/c/dc0bb3cac090818baa859a5c084ad2b558b6b714.jpeg)

In that case our sidebar data could get lost accidentally, if a user removes all unused config nodes (unaware that our sidebar data is stored in one of these config nodes...).

Hopefully that is a bit clear?

---

<div class="post-metadata">

**Author:** ![gregorius](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/gregorius/32/73816_2.png) [@gregorius](https://discourse.nodered.org/u/gregorius)\
**Post date:** [14 October 2023 15:42 UTC](https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020/8 "2023-10-14T15:42:14Z")

</div>

> [@TotallyInformation](#):
>
> It would be really nice to have some process that let people submit documentation

Isn't this [repo](https://github.com/node-red/node-red.github.io/tree/master/docs) the documentation of [nodered.org](http://nodered.org)? If so, a PR there would be probably the right place.

> [@ralphwetzel](#):
>
> As it's a node registered with category defined `config`, it won't show up in the (left-hand) palette sidebar.

👍 Thanks @ralphwetzel I didn't notice the category being `config`

> [@ralphwetzel](#):
>
> That said, I think (yet haven't tested) it's not necessary to create html elements for the stored data (and then disable those);

So the html would only be included in the sidebar `.html`? That would make sense and would keep the code DRY.

> [@BartButenaers](#):
>
> That is why I explained that ´hasUsers´ needs to be set to false. Because our config node is not linked to another node, so it would end up incorrectly between the unused config nodes:

Ok, I think I'll have a play around and see whether I can get something up and running

Thanks for all the clarification - much ☀ to all!

---

<div class="post-metadata">

**Author:** ![ralphwetzel](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/ralphwetzel/32/53713_2.png) [@ralphwetzel](https://discourse.nodered.org/u/ralphwetzel)\
**Post date:** [14 October 2023 16:16 UTC](https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020/9 "2023-10-14T16:16:02Z")

</div>

> [@gregorius](#):
>
> So the html would only be included in the sidebar `.html`? That would make sense and would keep the code DRY.

There's still the need to define a `.html` file for the config node - ~~or to include it `html`ish definition in the `.html` file of the sidebar~~ (not sure what happens when you mix definitions for plugin & node in one `.html` file; better safe to go with separated files). It _shouldn't_ be necessary though to create ui elements and disable them:

> [@BartButenaers](#):
>
> ```html
> <!-- The html for the config node screen -->
> <script type="text/x-red" data-template-name="your_config_node_name">
> <div class="form-tips">This config node is read-only, because it stores the information entered in the 'Your plugin name' sidebar.</div>
> <!-- The following element definitions shouldn't be necessary!
> <div class="form-row" id="auto_layout_config_name_div">
> <label for="node-config-input-name"><i class="icon-tag"></i> Name</label>
> <input type="text" id="node-config-input-name" disabled>
> </div>
> <div class="form-row">
> <label for="node-config-input-someData"><i class="fa fa-terminal"></i> Some data</label>
> <input type="text" id="node-config-input-someData" disabled>
> </div>
> -->
> </script>
> 
> ```

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [14 October 2023 18:21 UTC](https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020/10 "2023-10-14T18:21:30Z")

</div>

> [@gregorius](#):
>
> If so, a PR there would be probably the right place.

I know _where_ and I believe I've submitted a PR before. But what I was trying to get across was that it actually isn't easy to update the node-red docs. Certainly not something that you can do in a few minutes.

Having an easier staging place would really help more people submit things that could then be triaged for the main docs, an FAQ in the forum or the cookbook, the wording style could be adjusted, locations chosen - multiple people could help. Then doing the final submission and PR would also be a lot easier.

---

<div class="post-metadata">

**Author:** ![gregorius](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/gregorius/32/73816_2.png) [@gregorius](https://discourse.nodered.org/u/gregorius)\
**Post date:** [14 October 2023 19:00 UTC](https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020/11 "2023-10-14T19:00:52Z")

</div>

In all seriousness what you speak of is a wiki. PRs are great for code and wikis are great for documentation.

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [15 October 2023 10:37 UTC](https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020/12 "2023-10-15T10:37:18Z")

</div>

From the wiki's back to the sidebar 😋

@gregorius: it is also sometimes useful to make some features of your sidebar available as a flow editor _ **action** _.

1. Suppose you have e.g. a button on your sidebar, which calls a function when being clicked:

```auto
$("#do-something-button").click(function() {
    doSomething();
})

```

2. In your sidebar html file you can also register an action for that function:

```auto
RED.actions.add("core:my-sidebar-action",function() {
   doSomething();
});

```

This way your sidebar functionality becomes available in the flow editor actions list.

Although I assume the "core" (in the action name) should be replaced by something custom...

---

<div class="post-metadata">

**Author:** ![gregorius](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/gregorius/32/73816_2.png) [@gregorius](https://discourse.nodered.org/u/gregorius)\
**Post date:** [16 October 2023 08:24 UTC](https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020/13 "2023-10-16T08:24:27Z")

</div>

> [@BartButenaers](#):
>
> ```auto
> RED.events.on('runtime-state', function() {
> RED.events.off('runtime-state', function() {});
> 
> ```

I changed this to be:

```auto
var initialiseConfigNodeOnce = () => {
      RED.events.off('runtime-state', initialiseConfigNodeOnce);
....
};
RED.events.on('runtime-state', initialiseConfigNodeOnce);

```

I assume you want that code to be executed once and once only but it was being executed each deployment.

Btw in the configuration node panel, the node isn't setup, i.e. doesn't contain the current value:

 ![Screen Shot 2023-10-16 at 10.16.30](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/a/b/ab1e473c826e6e781ad6cc5466ad5b5a0d1d57b4.png)

Is there something else that needs to happen for that panel to be correctly setup? The html shown is from the sidebar html file, not the node definition...

---

<div class="post-metadata">

**Author:** ![kuema](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/kuema/32/6542_2.png) [@kuema](https://discourse.nodered.org/u/kuema)\
**Post date:** [16 October 2023 08:34 UTC](https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020/14 "2023-10-16T08:34:32Z")

</div>

> [@gregorius](#):
>
> `RED.events.on('runtime-state', initialiseConfigNodeOnce);`

Since `RED.events` is an EventEmitter, you could use `RED.events.once()` instead, so you could save the `RED.events.off()` in your callback.

---

<div class="post-metadata">

**Author:** ![gregorius](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/gregorius/32/73816_2.png) [@gregorius](https://discourse.nodered.org/u/gregorius)\
**Post date:** [16 October 2023 08:39 UTC](https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020/15 "2023-10-16T08:39:29Z")

</div>

> [@kuema](#):
>
> RED.events.once()

I was thinking the same:

 ![Screen Shot 2023-10-16 at 10.38.52](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/1/1/11383462aa5dc6db0d19e04efc4f90eff50eeb93.png)

but my browser told me something else ☹

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [16 October 2023 08:57 UTC](https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020/16 "2023-10-16T08:57:07Z")

</div>

> [@gregorius](#):
>
> the node isn't setup, i.e. doesn't contain the current value:

I had something similar in the beginning, due to 2 reasons:

- Every time the user changes something in your sidebar (i.e. dropdown value, input field value, ...), you need to store the updated data immediately in your config node. Perhaps you have added an onchange event handler to your sidebar input element, but you did not tab away from that field (so the event is not triggered and the data is not synced toward your config node)? Best to put a `debugger` statement in your code and check whether the updated data is stored into your config node.

- After I refreshed my flow editor window, my config node was empty again because my sidebar was filled to early. That is why I used the "runtime-state" event: because when you run your code earlier, the config node was not loaded yet (by the flow editor) so your sidebar thinks incorrectly no config node yet, and it creates a new empty one.

---

<div class="post-metadata">

**Author:** ![kuema](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/kuema/32/6542_2.png) [@kuema](https://discourse.nodered.org/u/kuema)\
**Post date:** [16 October 2023 09:09 UTC](https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020/17 "2023-10-16T09:09:16Z")

</div>

> [@gregorius](#):
>
> but my browser told me something else ☹

Aaah, sorry! My bad... I was a bit quick there.

I thought it refers to the runtime code, not the editor. Then ignore what I've said... 😅

---

<div class="post-metadata">

**Author:** ![gregorius](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/gregorius/32/73816_2.png) [@gregorius](https://discourse.nodered.org/u/gregorius)\
**Post date:** [16 October 2023 09:35 UTC](https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020/18 "2023-10-16T09:35:06Z")

</div>

> [@BartButenaers](#):
>
> I had something similar in the beginning, due to 2 reasons:

Solved the problem, the node that is defined is the config and should have a different type - I was using the same type for tab and config node. The html (`data-template-name`) defined in the config node is then shown in the property panel when opened via the configuration nodes menu point.

I.e. the html that we deleted above is the html that is shown in the configuration panel!

---

<div class="post-metadata">

**Author:** ![gregorius](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/gregorius/32/73816_2.png) [@gregorius](https://discourse.nodered.org/u/gregorius)\
**Post date:** [16 October 2023 15:38 UTC](https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020/19 "2023-10-16T15:38:45Z")

</div>

So I've created my first sidebar plugin by converting the [flow2uml](https://www.npmjs.com/package/@gregoriusrippenstein/node-red-contrib-flow2uml) node from palette to config node with sidebar menu:

![Screen Shot 2023-10-16 at 17.37.35](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/0/e/0e5bf7468d6b45f6d51c034da6247cdf6e618039.png)

I also pulled [all this code](https://github.com/gorenje/node-red-contrib-nodedev/tree/main/nodes/templates) (`sidebar` templates) into the [nodedev](https://www.npmjs.com/package/@gregoriusrippenstein/node-red-contrib-nodedev) set of nodes so that it's now possible to generate sidebar nodes using the NodeFactory:

 ![Screen Shot 2023-10-16 at 17.34.44](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/5/6/5675b0caa9f715992e699e976945649ad8956483.png)

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [16 October 2023 16:25 UTC](https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020/20 "2023-10-16T16:25:54Z")

</div>

> [@gregorius](#):
>
> it's now possible to generate sidebar nodes using the NodeFactory

Cool. A fast student in our classroom...  
Due to your new NodeFactory feature this tutorial has become already obsolete for you 😉

[Next page](https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020.md?page=2)
