diff --git a/docs/.vitepress/config.js b/docs/.vitepress/config.js
index 801cf41c2..ea3133031 100644
--- a/docs/.vitepress/config.js
+++ b/docs/.vitepress/config.js
@@ -136,6 +136,7 @@ export default ({ mode }) => {
{ text: 'ui-chart', link: '/nodes/widgets/ui-chart' },
{ text: 'ui-dropdown', link: '/nodes/widgets/ui-dropdown' },
{ text: 'ui-event', link: '/nodes/widgets/ui-event' },
+ { text: 'ui-file-input', link: '/nodes/widgets/ui-file-input' },
{ text: 'ui-form', link: '/nodes/widgets/ui-form' },
{ text: 'ui-gauge', link: '/nodes/widgets/ui-gauge' },
{ text: 'ui-markdown', link: '/nodes/widgets/ui-markdown' },
diff --git a/docs/nodes/widgets/ui-file-input.md b/docs/nodes/widgets/ui-file-input.md
new file mode 100644
index 000000000..d4550b341
--- /dev/null
+++ b/docs/nodes/widgets/ui-file-input.md
@@ -0,0 +1,58 @@
+---
+description: The File Upload widget allows users to upload files to Node-RED.
+props:
+ Group: Defines which group of the UI Dashboard this widget will render in.
+ Size: Controls the width of the dropdown with respect to the parent group. Maximum value is the width of the group.
+ Label:
+ description: The text shown to the user, explaining what the user should upload.
+ Icon:
+ description: Defaults to "paperclip". The icon shown to the left of the input field. See the full list of icons here.
+ Accept:
+ description: String representation of the "allow" file type selectors. See full list of options here.
+ Multiple:
+ description: Allow end-users to upload multiple files at once. Each file will be sent as a unique message.
+---
+
+# File Upload
+
+The File Upload widget allows users to upload files to Node-RED. The widget can be configured to accept specific file types and allow for multiple files.
+
+## Properties
+
+
+
+## Output
+
+```js
+{
+ payload: ,
+ file: {
+ name: ,
+ type: ,
+ size:
+ },
+ topic: ,
+}
+```
+
+## Current Limitations
+
+_Currently_, the File Upload widget is limited by a maximum file size defined by the Websocket connection. The default maximum here is 5MB. This can be increased by modifying the `maxHttpBufferSize` property in the `settings.js` file in the Node-RED installation directory:
+
+```
+dashboard: {
+ maxHttpBufferSize: 1e8 // size in bytes, example: 100 MB
+}
+```
+
+Read more about Dashboard configuration in the `settings.js` [here](/user/settings.html#maxhttpbuffersize).
+
+Note that we do have plans to improve this behavior by chunking files into smaller parts, and reassembling them on the server side. This will allow for larger files to be uploaded, and will be implemented in a future release.
+
+## Example
+
+![Example of a File Upload](/images/node-examples/ui-file-input-select.png "Example of a File Upload"){data-zoomable}
+_Screenshot to show an example file input, when ready to have a file selected_
+
+![Example of a File Upload](/images/node-examples/ui-file-input-chosen.png "Example of a File Upload"){data-zoomable}
+_Screenshot to show an example file input, when a file has been selected, and is ready for "Upload"_
diff --git a/docs/public/images/node-examples/ui-file-input-chosen.png b/docs/public/images/node-examples/ui-file-input-chosen.png
new file mode 100644
index 000000000..24650f91f
Binary files /dev/null and b/docs/public/images/node-examples/ui-file-input-chosen.png differ
diff --git a/docs/public/images/node-examples/ui-file-input-select.png b/docs/public/images/node-examples/ui-file-input-select.png
new file mode 100644
index 000000000..b6c6836be
Binary files /dev/null and b/docs/public/images/node-examples/ui-file-input-select.png differ
diff --git a/nodes/widgets/locales/en-US/ui_file_input.html b/nodes/widgets/locales/en-US/ui_file_input.html
new file mode 100644
index 000000000..ef4000587
--- /dev/null
+++ b/nodes/widgets/locales/en-US/ui_file_input.html
@@ -0,0 +1,18 @@
+
\ No newline at end of file
diff --git a/nodes/widgets/ui_file_input.html b/nodes/widgets/ui_file_input.html
new file mode 100644
index 000000000..8fe5763be
--- /dev/null
+++ b/nodes/widgets/ui_file_input.html
@@ -0,0 +1,120 @@
+
+
+
diff --git a/nodes/widgets/ui_file_input.js b/nodes/widgets/ui_file_input.js
new file mode 100644
index 000000000..301ce4433
--- /dev/null
+++ b/nodes/widgets/ui_file_input.js
@@ -0,0 +1,35 @@
+// const datastore = require('../store/data.js')
+
+module.exports = function (RED) {
+ function FileInputNode (config) {
+ const node = this
+
+ // create node in Node-RED
+ RED.nodes.createNode(this, config)
+
+ // this ndoe need to store content/value from UI
+ node.value = null
+
+ // which group are we rendering this widget
+ const group = RED.nodes.getNode(config.group)
+
+ const evts = {
+ onAction: true
+ }
+
+ // get max file size supported
+ const MAX_FILESIZE_DEFAULT = 1e6
+ const maxFileSize = RED.settings.dashboard?.maxHttpBufferSize || MAX_FILESIZE_DEFAULT
+
+ config.maxFileSize = maxFileSize
+
+ // inform the dashboard UI that we are adding this node
+ group.register(node, config, evts)
+
+ node.on('close', async function (done) {
+ done()
+ })
+ }
+
+ RED.nodes.registerType('ui-file-input', FileInputNode)
+}
diff --git a/package.json b/package.json
index 9213bd803..958a6abcc 100644
--- a/package.json
+++ b/package.json
@@ -122,6 +122,7 @@
"ui-theme": "nodes/config/ui_theme.js",
"ui-form": "nodes/widgets/ui_form.js",
"ui-text-input": "nodes/widgets/ui_text_input.js",
+ "ui-file-input": "nodes/widgets/ui_file_input.js",
"ui-button": "nodes/widgets/ui_button.js",
"ui-button-group": "nodes/widgets/ui_button_group.js",
"ui-dropdown": "nodes/widgets/ui_dropdown.js",
diff --git a/ui/src/stylesheets/common.css b/ui/src/stylesheets/common.css
index 85c01cefc..e9e225313 100644
--- a/ui/src/stylesheets/common.css
+++ b/ui/src/stylesheets/common.css
@@ -13,7 +13,7 @@
/* main */
--nrdb-main-padding: 12px;
/* widget sizing */
- --widget-row-height: 42px;
+ --widget-row-height: 48px;
}
body {
@@ -60,6 +60,18 @@ main {
fill: #bbb;
}
+/**
+* Anchor
+*/
+
+.nrdb-anchor {
+ cursor: pointer;
+ color: rgb(var(--v-theme-primary));
+}
+.nrdb-anchor:hover {
+ color: rgb(var(--v-theme-primary-darken-1));
+}
+
/**
* Placeholder
*/
diff --git a/ui/src/widgets/index.mjs b/ui/src/widgets/index.mjs
index 238a988e8..853c7c332 100644
--- a/ui/src/widgets/index.mjs
+++ b/ui/src/widgets/index.mjs
@@ -4,6 +4,7 @@ import UIChart from './ui-chart/UIChart.vue'
import UIControl from './ui-control/UIControl.vue'
import UIDropdown from './ui-dropdown/UIDropdown.vue'
import UIEvent from './ui-event/UIEvent.vue'
+import UIFileInput from './ui-file-input/UIFileInput.vue'
import UIForm from './ui-form/UIForm.vue'
import UIGauge from './ui-gauge/UIGauge.vue'
import UIMarkdown from './ui-markdown/UIMarkdown.vue'
@@ -24,6 +25,7 @@ export {
UIControl,
UIDropdown,
UIEvent,
+ UIFileInput,
UIForm,
UIGauge,
UIMarkdown,
@@ -48,6 +50,7 @@ export default {
'ui-control': UIControl,
'ui-dropdown': UIDropdown,
'ui-event': UIEvent,
+ 'ui-file-input': UIFileInput,
'ui-form': UIForm,
'ui-gauge': UIGauge,
'ui-markdown': UIMarkdown,
diff --git a/ui/src/widgets/ui-file-input/UIFileInput.vue b/ui/src/widgets/ui-file-input/UIFileInput.vue
new file mode 100644
index 000000000..5ca1f7ad1
--- /dev/null
+++ b/ui/src/widgets/ui-file-input/UIFileInput.vue
@@ -0,0 +1,177 @@
+
+