Update Dec 2024: The web components now have their own website which acts as docs, demos and tests.
https://wc.totallyinformation.net
OK, after some time playing with these, I think they are ready to share with the world! Though please note that you should certainly treat these as EXPERIMENTAL for now because I'm still learning and undoubtedly I'll need to make more breaking changes.
BUT, they work, if a little simplistically.
What are they? You ask! Well, they are a set of modern web components. Which is to say, when you load the files, you get new HTML tags to play with. Those tags are designed to help you build data-driven web pages (of course, hence I'm relating these to uibuilder). They should, if I get them right, GREATLY simplify building a web UI that can be driven from Node-RED.
If you are truly adventurous, you can dig into the documentation for the new ECMA module version of the uibuilder front-end library and try using the configuration driven UI builder feature as well.
But for now, you can, at least, very easily try out the components along with the new client and the shiny new stylesheet that automatically or manually adjusts to light/dark layouts.
To use the components, you will firstly need node-red-contrib-uibuilder installed. Then use uibuilder's library manager to install totallyinformation/web-components
which will install the library direct from GitHub.
Now add a uibuilder node using the "blank" template. Deploy. Then change the index.html file to be something like this:
<!doctype html>
<html lang="en"><head>
<meta charset="utf-8">
<title>Web Component Test: simple-container and simple-card</title>
<style>
@import url("./uib-brand.css");
/* Can override the base hue and the accent colours and other things too */
/* :root {
--brand-hue: 200;
--accent-offset: 30;
} */
</style>
<script type="module" async >
// These assume you are using Node-RED/uibuilder
import '../uibuilder/vendor/@totallyinformation/web-components/libs/uibuilder.module.js' // Adds `uibuilder` and `$` to globals
import '../uibuilder/vendor/@totallyinformation/web-components/components/simple-container.js'
import '../uibuilder/vendor/@totallyinformation/web-components/components/simple-card.js'
import '../uibuilder/vendor/@totallyinformation/web-components/components/uib-theme-changer.js'
import '../uibuilder/vendor/@totallyinformation/web-components/components/labelled-value.js'
import '../uibuilder/vendor/@totallyinformation/web-components/components/button-send.js'
import '../uibuilder/vendor/@totallyinformation/web-components/components/container-br.js'
// An EventListener added here cannot pick up the initial setup but will pick up later events
// However, uibuilder and $ are available.
uibuilder.start()
</script>
</head><body>
<uib-theme-changer></uib-theme-changer>
<h1>Demonstrating Web Components</h1>
<p>This example uses <code><simple-container</code> and <code><simple-card></code>.</p>
<p>
The container component uses a flex row layout. The card component has header and footer slots.
</p>
<simple-container>
<simple-card>
Hello, in a card<br>
<labelled-value label="My Value" value="42">°</labelled-value>
<span slot="header">Some other header</span>
<span slot="footer">Some footer</span>
</simple-card>
<simple-card name="This Is a name">
Another card
<labelled-value label="My Other Value" value="Fourty Two">°</labelled-value>
</simple-card>
<simple-card id="card3" data-something="Hello">
Card #3
</simple-card>
<container-br></container-br>
<div>
<button-send data-something="Something interesting">Send Me to Somewhere 😀</button-send>
</div>
</simple-container>
<script>
// Event Listeners set in module scripts wont get set up early enough to pick up the initial component load events
// BUT an ordinary script like this WILL trigger early enough.
// HOWEVER, this triggers so early that if you load uibuilder in a module script, it
// wont be available here immediately. You would have to wait for ~300 ms.
// document.addEventListener('simple-card:connected', e => {
// console.log('>> (document) EVENT simple-card:connected >>', e.target, e.detail)
// })
// This CAN pick up the initial setup event
// document.addEventListener('simple-card:attribChanged', e => {
// console.log('>> (document) EVENT simple-card:attribChanged >>', e.target, e.detail)
// })
// Things set up in uibuilder won't be available here for ~300ms
// setTimeout(function(){
// console.log('HELLO', window.$)
// $('#card3').setAttribute("name", "helloButton")
// }, 300)
// We can also listen at the component instance level:
// const sc = document.getElementsByTagName('simple-card')
// for (const i of sc) {
// // When the component constructor is run
// // i.addEventListener('simple-card:construction', e => {
// // console.log('>> EVENT simple-card:construction >>', e)
// // })
// // When the component instance is connected to the DOM
// // i.addEventListener('simple-card:connected', e => {
// // console.log('>> EVENT simple-card:connected >>', e)
// // })
// // When the component instance is disconnected from the DOM
// // i.addEventListener('simple-card:disconnected', e => {
// // console.log('>> EVENT simple-card:disconnected >>', e)
// // })
// }
</script>
</body></html>
Open the new web page and marvel at how easy it is to create something nice with so little effort!
Not everything works brilliantly as yet and the documentation is lagging behind for sure but hopefully it gives you an idea of what I'm thinking about for another very easy way of building data-driven web apps via Node-RED.
I'll do an example with the config-driven settings soon as well.
Components available now:
Name | Description |
---|---|
button-send |
A pre-defined button that fires an event and sends a uibuilder msg when clicked. Includes attribs in the sent data. |
container-br |
Like <br> for flex layouts. Forces a new row in a simple-container (or any other flex row container) |
data-list |
Data-driven UL/OL. Takes a JSON or JavaScript object or array of objects and outputs a formatted list. |
definition-list |
Similar to data-list but outputs a DL instead. |
html-include |
Dynamically load external HTML content very easily without needing an iFrame. |
labelled-value |
Text output with a label. |
simple-card |
A card container with optional header and footer. |
simple-container |
A UI container for easy, automated layout of contained elements (specifically cards). |
syntax-highlight |
A simple, easy to use JSON object highlight element. Auto settings for different types of uibuilder messages or manually pass the data. |
uib-theme-changer |
This only works with the uib-brand stylesheet or something crafted to be like it. Switch between light/dark/auto schemes, shift the base hue, contrast ratio, and 2 accent colours. |
With more to come, here is the list of things I'm thinking of. There will certainly be more.
Name | Description |
---|---|
simple-input |
An input tag with a label. With option to be part of a form (button submission) or to give output on lost focus. |
simple-button |
A button that triggers a custom document event and sends to uibuilder (if available). Automatically includes attrib and prop data, id, name, etc. Includes basic formatting and a slot for text (which allows some HMTL formatting). |
visual-log |
Creates a log element on-page that expands to a set number of lines then drops from the start |
simple-table |
Takes a JSON or JavaScript object or array and displays the contents in a simple table format. |
data-table |
Similar to simple-table but with more options such as nested tables and multiple headers/bodies. Probably also with CRUD controls. |
data-card |
A data-driven card with headers, footers, etc. Also acts as a container for other HTML as part of a grid view. |
grid-view |
A controllable grid layout. |
chart-* |
Various different chart outputs using different libraries. Chart.js, Uplot, EChart |
on-off |
A dedicated on/off button. |
simple-dialog |
Simple wrapper for a dialog box with options for modal, button list |
simple-pie |
Web Components using UnknownHTMLElements for better semantic HTML - DEV Community |
nav-bar |