# Write node forms using Vue 3 and JSON Schema

**URL:** https://discourse.nodered.org/t/write-node-forms-using-vue-3-and-json-schema/96727
**Category:** Developing Nodes
**Created:** [23 April 2025 20:04 UTC](https://discourse.nodered.org/t/write-node-forms-using-vue-3-and-json-schema/96727 "2025-04-23T20:04:12Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![AllanOricil](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/allanoricil/32/106911_2.png) [@AllanOricil](https://discourse.nodered.org/u/AllanOricil)
#### Post date: [23 April 2025 20:04 UTC](https://discourse.nodered.org/t/write-node-forms-using-vue-3-and-json-schema/96727/1 "2025-04-23T20:04:12Z")

</div>

Soon you will be able to test my framework for writting node forms using Vue 3 and JSON Schema. This will enable the creation of more complex config forms and write code in an modern way.

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

Directory structure

```auto
.
├── src/
│ └── nodes/
│ └── node-1/
│ ├── schemas/
│ │ ├── config.js
│ │ ├── iput.js
│ │ ├── output-1.js
│ │ ├── output-2.js
│ │ ├── ...
│ │ └── output-n.js
│ ├── client/
│ │ ├── locales/
│ │ │ ├── docs/
│ │ │ │ ├── en-US.md
│ │ │ │ ├── de.md
│ │ │ │ └── ...
│ │ │ └── labels/
│ │ │ ├── en-US.json
│ │ │ ├── de.json
│ │ │ └── ...
│ │ ├── assets/
│ │ │ └── icons/
│ │ │ └── vue.svg
│ │ ├── form.vue
│ │ └── index.js
│ └── server/
│ └── index.js
└── package.json

```

src/nodes/node-1/client/index.js

```js
import MyComponentForm from "./form.vue";
import MyComponentFormSchema from "../schemas/config.js";
import { registerType } from "@nrg/core/client";

export default registerType({
  category: "function",
  color: "#FFFFFF",
  inputs: 1,
  outputs: 1,
  icon: "vue.png", // TODO: check if I can load base64 asset
  form: MyComponentForm, // NOTE: vue form to change node properties
  schema: MyComponentFormSchema, // NOTE: the same source of truth for defaults and credentials in both server and client.
});

```

src/nodes/node-1/client/form.vue

```html
<template>
  <div>
    <div class="form-row">
      <label><i class="fa fa-tag"></i> Username</label>
      <NodeRedInput
        v-model:value="node.credentials.username"
        :error="errors['node.credentials.username']"
      />
    </div>
    <div class="form-row">
      <label><i class="fa fa-tag"></i> Password</label>
      <NodeRedInput
        v-model:value="node.credentials.password"
        type="password"
        :error="errors['node.credentials.password']"
      />
    </div>
    <div class="form-row">
      <label>Typed Input</label>
      <NodeRedTypedInput
        v-model:value="node.myProperty"
        :types="types"
        :error="errors['node.myProperty']"
      />
    </div>
    <div class="form-row">
      <label>Typed Input 2</label>
      <NodeRedTypedInput
        v-model:value="node.myProperty2"
        :error="errors['node.myProperty2']"
      />
    </div>
    <div class="form-row">
      <label>Config Input</label>
      <NodeRedConfigInput
        v-model:value="node.remoteServer"
        type="remote-server"
        :error="errors['node.remoteServer']"
      />
    </div>
    <div class="form-row">
      <label>Select Input</label>
      <NodeRedSelectInput
        v-model:value="node.country"
        :options="countries"
        :error="errors['node.country']"
      />
    </div>
    <div class="form-row">
      <label>MultiSelect Input</label>
      <NodeRedSelectInput
        v-model:value="node.fruit"
        :options="fruits"
        multiple
        :error="errors['node.fruit']"
      />
    </div>
    <div class="form-row">
      <label>Select Input</label>
      <NodeRedSelectInput
        v-model:value="node.number"
        :options="numbers"
        :error="errors['node.number']"
      />
    </div>
    <div class="form-row">
      <label>Select Input</label>
      <NodeRedSelectInput
        v-model:value="node.object"
        :options="objects"
        multiple
        :error="errors['node.object']"
      />
    </div>
    <div class="form-row">
      <label>Select Input</label>
      <NodeRedSelectInput
        v-model:value="node.array"
        :options="arrays"
        :error="errors['node.array']"
      />
    </div>
    <div class="form-row">
      <label>Editor with default height 200px and JSON</label>
      <NodeRedEditorInput
        v-model:value="node.jsontest"
        :error="errors['node.jsontest']"
      />
    </div>
    <div class="form-row">
      <label>Editor with custom height and CSS</label>
      <NodeRedEditorInput
        v-model:value="node.csstest"
        language="css"
        style="height: 100px"
        :error="errors['node.csstest']"
      />
    </div>
  </div>
</template>

<script>
export default {
  props: {
    node: {
      type: Object,
      required: true,
    },
    errors: {
      type: Object,
      default: () => ({}),
    },
  },
  data() {
    return {
      types: ["str", "msg"],
      countries: [
        { value: "usa", label: "usa" },
        { value: "argentina", label: "argentina" },
        { value: "brasil", label: "brasil" },
      ],
      fruits: [
        { value: "apple", label: "apple" },
        { value: "melon", label: "melon" },
        { value: "raspberry", label: "raspberry" },
      ],
      numbers: [
        { value: "1", label: "1" },
        { value: "2", label: "2" },
        { value: "3", label: "3" },
      ],
      objects: [
        { value: JSON.stringify({ test: "a" }), label: "a" },
        { value: JSON.stringify({ test: "b" }), label: "b" },
        { value: JSON.stringify({ test: "c" }), label: "c" },
      ],
      arrays: [
        { value: JSON.stringify(["a"]), label: "a" },
        { value: JSON.stringify(["b"]), label: "b" },
        { value: JSON.stringify(["c"]), label: "c" },
      ],
    };
  },
};
</script>

<style scoped>
.label {
  width: 100%;
}
</style>

```

---

<div class="post-metadata">

### Author: ![AllanOricil](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/allanoricil/32/106911_2.png) [@AllanOricil](https://discourse.nodered.org/u/AllanOricil)
#### Post date: [2 May 2025 22:42 UTC](https://discourse.nodered.org/t/write-node-forms-using-vue-3-and-json-schema/96727/2 "2025-05-02T22:42:24Z")

</div>

If you want a preview, install this node in your node-red instance.

Node-RED version \>= 4.0.9

> **[GitHub - AllanOricil/node-red-vue-inputs-experiments: Wrapping node-red form widgets using Vue to enable...](https://github.com/AllanOricil/node-red-vue-inputs-experiments)**
>
> Wrapping node-red form widgets using Vue to enable building forms using Vue

It is very messy because most of the code there is going to be packaged and integrated during bundling. The only code you will need to provide once I'm done is the schema.js and the form.vue.

This build is still using an old idea I had where you declare config and credentials using decorator called @config. You will notice that `Typed Input 2` isn't saved once the node changes are deployed, and the reason is because the server (the source of truth) doesn't have a prop annotated with @config for it. I added that field to demonstrate that the server controls the props and credentials that can be updated from the client.

---

<div class="post-metadata">

### Author: ![AllanOricil](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/allanoricil/32/106911_2.png) [@AllanOricil](https://discourse.nodered.org/u/AllanOricil)
#### Post date: [4 May 2025 21:58 UTC](https://discourse.nodered.org/t/write-node-forms-using-vue-3-and-json-schema/96727/3 "2025-05-04T21:58:58Z")

</div>

Any suggestions of components you would like to have available besides these ones?

> **[node-red-vue-inputs-experiments/core/client/components at main ·...](https://github.com/AllanOricil/node-red-vue-inputs-experiments/tree/main/core%2Fclient%2Fcomponents)**
>
> Wrapping node-red form widgets using Vue to enable building forms using Vue - AllanOricil/node-red-vue-inputs-experiments

---

<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: [3 July 2025 21:59 UTC](https://discourse.nodered.org/t/write-node-forms-using-vue-3-and-json-schema/96727/4 "2025-07-03T21:59:46Z")

</div>

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