# Dynamic UI creation?

**URL:** <https://discourse.nodered.org/t/dynamic-ui-creation/100284>\
**Category:** Dashboard\
**Created:** [30 January 2026 18:54 UTC](https://discourse.nodered.org/t/dynamic-ui-creation/100284 "2026-01-30T18:54:31Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Jibun-no-Kage](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/jibun-no-kage/32/99316_2.png) [@Jibun-no-Kage](https://discourse.nodered.org/u/Jibun-no-Kage)\
**Post date:** [30 January 2026 18:54 UTC](https://discourse.nodered.org/t/dynamic-ui-creation/100284/1 "2026-01-30T18:54:31Z")

</div>

Is there, within one of the various UI frameworks for NR, that would allow dynamic UI creation? Here is the use case, I have a JSON, that changes from time to time, I want to create a button for each top level property in the JSON.

The JSON is rather simplistic...

```auto
[
    {
        "Name": "One",
        "Key": "1"
    },
    {
        "Name": "Two",
        "Key": "2"
    }
]

```

Would love to create a follow on when the JSON is loaded... creates two buttons (per the number in the JSON file), where the button label set to name, and payload to key, for example. Anyone do something similar?

---

<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:** [30 January 2026 20:12 UTC](https://discourse.nodered.org/t/dynamic-ui-creation/100284/2 "2026-01-30T20:12:26Z")

</div>

Certainly, UIBUILDER can do this for you - you may need to transform the input JSON slightly to fit in with the `uib-element` node's "Form" setting. There is a built-in example that shows all of the different `uib-element` settings including forms. The output is a low-code JSON format that the uibuilder client library can convert direct to an HTML Form structure. You also get automatic handling of things like button clicks. You can even do the HTML conversion server-side if you prefer.

There are other ways to do this with UIBUILDER as well, but that may be the simplest.

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [30 January 2026 21:31 UTC](https://discourse.nodered.org/t/dynamic-ui-creation/100284/3 "2026-01-30T21:31:39Z")

</div>

Pretty simple stuff with #dashboard-2 ([@flowfuse/node-red-dashboard](https://dashboard.flowfuse.com/))

![chrome_FW5I09MHGD](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/9/4/94acf3a850ab90243e87e32ccb2f49cd2490a18e.gif)

Here is the flow

```auto
[{"id":"28853be7be79a556","type":"ui-template","z":"b6818da1a76c1147","group":"638a7463e2421854","page":"","ui":"","name":"","order":1,"width":"6","height":"2","head":"","format":"<template>\n <v-row class=\"\" dense>\n <v-col cols=\"auto\" v-for=\"item in msg?.payload || []\" :key=\"item.Key\">\n <v-btn @click=\"sendPayload(item)\" color=\"primary\" variant=\"outlined\">\n {{ item.Name }}\n </v-btn>\n </v-col>\n </v-row>\n</template>\n\n<script>\nexport default {\n methods: {\n sendPayload(item) {\n this.send({ payload: item.Key, topic: item.Name });\n }\n }\n}\n</script>\n\n\n<style>\n div.dynamic-buttons.nrdb-ui-widget.nrdb-ui-template {\n overflow-y: unset;\n }\n</style>","storeOutMessages":true,"passthru":false,"resendOnRefresh":true,"templateScope":"local","className":"dynamic-buttons","x":400,"y":520,"wires":[["c72543bdea5d14e2"]]},{"id":"e90416a364eadebd","type":"ui-button","z":"b6818da1a76c1147","group":"638a7463e2421854","name":"","label":"Random Buttons","order":2,"width":0,"height":0,"emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"","icon":"","iconPosition":"left","payload":"","payloadType":"date","topic":"topic","topicType":"msg","buttonColor":"","textColor":"","iconColor":"","enableClick":true,"enablePointerdown":false,"pointerdownPayload":"","pointerdownPayloadType":"str","enablePointerup":false,"pointerupPayload":"","pointerupPayloadType":"str","x":350,"y":400,"wires":[["773952792e35e55e"]]},{"id":"773952792e35e55e","type":"function","z":"b6818da1a76c1147","name":"random array of items","func":"const randomCount = Math.floor(Math.random() * 10) + 1\n\nconst payload = []\n\nfor (let i = 1; i <= randomCount; i++) {\n payload.push({\n Name: i === 1 ? 'One' : i === 2 ? 'Two' : i === 3 ? 'Three' : i === 4 ? 'Four' : i === 5 ? 'Five' : i === 6 ? 'Six' : i === 7 ? 'Seven' : i === 8 ? 'Eight' : i === 9 ? 'Nine' : 'Ten',\n Key: i.toString()\n })\n}\n\nmsg.payload = payload\nreturn msg\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":360,"y":460,"wires":[["28853be7be79a556"]]},{"id":"c72543bdea5d14e2","type":"ui-notification","z":"b6818da1a76c1147","ui":"f1633f89193de4bc","position":"top right","colorDefault":false,"color":"#df9a9a","displayTime":"1","showCountdown":true,"outputs":1,"allowDismiss":true,"dismissText":"Close","allowConfirm":false,"confirmText":"Confirm","raw":false,"className":"","name":"","x":600,"y":520,"wires":[[]]},{"id":"638a7463e2421854","type":"ui-group","name":"Group Name","page":"2ccae6b36a109b4b","width":6,"height":1,"order":1,"showTitle":false,"className":"","visible":"true","disabled":"false","groupType":"default"},{"id":"f1633f89193de4bc","type":"ui-base","name":"My Dashboard","path":"/dashboard","appIcon":"","includeClientData":true,"acceptsClientConfig":["ui-notification","ui-control"],"showPathInSidebar":false,"headerContent":"page","navigationStyle":"default","titleBarStyle":"default","showReconnectNotification":true,"notificationDisplayTime":1,"showDisconnectNotification":true,"allowInstall":true},{"id":"2ccae6b36a109b4b","type":"ui-page","name":"dynamic elements","ui":"f1633f89193de4bc","path":"/dyn-elements","icon":"home","layout":"grid","theme":"ad84029195b8d5f1","breakpoints":[{"name":"Default","px":"0","cols":"3"},{"name":"Tablet","px":"576","cols":"6"},{"name":"Small Desktop","px":"768","cols":"9"},{"name":"Desktop","px":"1024","cols":"12"}],"order":1,"className":"","visible":"true","disabled":"false"},{"id":"ad84029195b8d5f1","type":"ui-theme","name":"Default Theme","colors":{"surface":"#ffffff","primary":"#0094CE","bgPage":"#eeeeee","groupBg":"#ffffff","groupOutline":"#cccccc"},"sizes":{"density":"default","pagePadding":"12px","groupGap":"12px","groupBorderRadius":"4px","widgetGap":"12px"}},{"id":"c56db59f1c10671d","type":"global-config","env":[],"modules":{"@flowfuse/node-red-dashboard":"1.30.2"}}]

```

---

<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:** [30 January 2026 21:55 UTC](https://discourse.nodered.org/t/dynamic-ui-creation/100284/4 "2026-01-30T21:55:37Z")

</div>

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/1/8/1872429de4ede09ff2120e04fd16c37116b144b3.png)

The input JSON:

```json
[
    {
        "id": "b1",
        "type": "button",
        "label": "Button 1",
        "value": "B1"
    },
    {
        "id": "b2",
        "type": "button",
        "label": "Button 2",
        "value": "B2"
    }
]

```

The output to Node-RED on button 1 press:

```json
{
  "payload":{"b1":"B1","b2":"B2","value":"B1"},
  "_ui":{
    "type":"eventSend","id":"b1","name":"b1","slotText":"Button 1","dataset":{},
    "form":{
      "id":"form-sform1","valid":true,
      "b1":{"id":"b1","name":"b1","valid":true,"type":"button","value":"B1"},
      "b2":{"id":"b2","name":"b2","valid":true,"type":"button","value":"B2"}
    },
    "props":{},"attribs":{"type":"button","label":"Button 1","value":"B1","onclick":"uibuilder.eventSend(event)","title":"Type: button"},"classes":[],"event":"click","altKey":false,"ctrlKey":false,"shiftKey":false,"metaKey":false,"pointerType":"mouse","nodeName":"BUTTON","clientId":"G9Y0IOGJgI01e9e8Hr03z","pageName":"index.html","tabId":"t783683","from":"client"},"_socketId":"ZPV2OPctCPEtKtNAAAAa","_uib":{"url":"uib-element-test","_socketId":"ZPV2OPctCPEtKtNAAAAa","recovered":false,"ip":"::1","referer":"https://localhost:3001/uib-element-test/","version":"7.6.0-src","clientId":"G9Y0IOGJgI01e9e8Hr03z","tabId":"t783683","pageName":"index.html","urlParams":{},"connections":1,"tls":true,"connectedTimestamp":"2026-01-30T21:47:33.667Z","connectHeaders":{"host":"localhost:3001","connection":"keep-alive","sec-ch-ua-platform":"\"Windows\"","user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36","accept":"*/*","x-clientid":"uibuilder; module; 7.6.0-src;","sec-ch-ua":"\"Not(A:Brand\";v=\"8\", \"Chromium\";v=\"144\", \"Google Chrome\";v=\"144\"","sec-ch-ua-mobile":"?0","dnt":"1","sec-fetch-site":"same-origin","sec-fetch-mode":"cors","sec-fetch-dest":"empty","referer":"https://localhost:3001/uib-element-test/","accept-encoding":"gzip, deflate, br, zstd","accept-language":"en-GB,en-US;q=0.9,en;q=0.8"}
  },
  "_msgid":"f77e9d0be61945c1"}

```

I simply tweaked the element example page to send the data:

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/b/8/b82a423369e72912217cb868d7f0dc060c89652a.png)

---

<div class="post-metadata">

**Author:** ![Jibun-no-Kage](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/jibun-no-kage/32/99316_2.png) [@Jibun-no-Kage](https://discourse.nodered.org/u/Jibun-no-Kage)\
**Post date:** [8 February 2026 03:27 UTC](https://discourse.nodered.org/t/dynamic-ui-creation/100284/5 "2026-02-08T03:27:08Z")

</div>

Thanks everyone, will give these a test run see what works for my use case.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [10 March 2026 03:27 UTC](https://discourse.nodered.org/t/dynamic-ui-creation/100284/6 "2026-03-10T03:27:53Z")

</div>

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.
