CSS Styling ui-button Widgets on Dashboard 2

The current state of my experiments with styling buttons.

Clicking on a button variously changes the icon, icon colour, text, text colour or background colour.

Round and square buttons retain their size and proportions at varying screen resolutions.
This avoids oddly shaped buttons on a dashboard using grid layout.
Note though that the spacing between these buttons does vary.

The buttons are constrained to multiples of the widget height setting to avoid borking horizontal alignment between widgets in a grid layout.

Code to follow, if it's of interest.

Observations:

  1. It is frustrating to need a function for every button to change the styling when it is clicked.
    A big enhancement would be if each button config had two class values, one for "on", one for "off". If both values are set, clicking the button toggles between them.
    eg Class on "green" Class off "red"
    (Even more relevant for the switch node, which has just two possible states "on" and "off")?
    Edit - Better: the button or switch retains it's state "on" or "off" and exposes it as a class. So we could style eg .myclass.on and .myclass.off differently.

  2. I have found it difficult to reliably initialise the button state. The above enhancement should allow a message to set the initial value (so that the button can be made to reflect the real world status)

  3. A button has a slight mouseover shadow effect. It seems to be absent from one or two of these buttons, I can't work out why.

  4. Once a widget property has been set via msg.ui_control it seems extraordinarily resilient even if that code is removed, apparently surviving a full deploy and a browser ctrl F5 reload.

  5. When a button is clicked, a brief shadow effect flows across it from the mouse location. It would be nice if we could tune the colour of this click effect.

It would be very interesting to see how other people are using the button widget.

6 Likes

As we have multi state switch, the multi state button seems also maybe valuable widget. So the regular button can be as is.

Search how to deal with hover and other states with browser developer tools and you can find classes which make the appearance of effect.

The effect called "ripple" and has separate html element which is tricky to examine with developer tools but if you find the classes you can manipulate those with ease.

Absolutely on board with this idea - could you raise an issue please? Although, I'd want it on the Switch, not button.

For me, a button an input widget, a switch maintains state and is clickable.

1 Like

I don't use switches on dashboards because they are horrible.

  • The label floats somewhere distant from the [representation of] the actual switch
    image

  • There is nothing to indicate that "switch" and the asymmetric dot and oval relate to each other. If I saw it on an unfamiliar dashboard I'd probably try to click on the word "switch" before the ugly graphic.

  • I have no idea how to style a switch to enhance the user's understanding. The whole thing seems irremediable.

Modern electrical devices increasingly use a button, perhaps on a remote control, to turn on and off. It's true for TVs, car engines, cookers.
Some of these buttons are overloaded by the addition of indicator LEDs.
It's inevitable that IOT dashboards will likewise use buttons where you would prefer a switch.

2 Likes

Would like to see a switch like this some day OOB.
I tried to get this through ui-template node (in DB1), but could not get the size to reduce to desired size. but the switch works.

switch

https://codepen.io/josetxu/pen/oNQXpoz

1 Like

You then need all other components with same look and feel. Not easiest task ...

1 Like

They should be connected and so clicking the label should indeed trigger the switch. But it doesn't. That should really be resolved. Probably needs an issue raising.

Incidentally, it also fails a quick accessibility check.

It's been resolved, just not yet released. Some users asked for only the switch to be interactive, some have asked for jusg the text and switch, some asked for the whole row... its now a config option thanks to @BartButenaers

2 Likes

I am interesrted

Yep, second that, interested

sizing

responsive1
round
square

[{"id":"69594495cf1ea8a1","type":"tab","label":"DB2 Buttons","disabled":false,"info":"","env":[]},{"id":"d34a0391580f1586","type":"group","z":"69594495cf1ea8a1","name":"Fixed Round Buttons","style":{"label":true},"nodes":["bd54913827144c1e","6eb27320b308af4d","722b745215f085f0","27ee1b05047db589","fb769b5b1ac7e460","00a210647991ac85"],"x":14,"y":19,"w":712,"h":122},{"id":"d35e14936c5225e4","type":"group","z":"69594495cf1ea8a1","name":"Responsive Buttons","style":{"label":true},"nodes":["0b3c7165b87d1ca0","57022ce1f218aad6","3efcba291e1d4ca7","bb86a78e2f17c1b7","0a460124e234d3b4","884f26d74da094c9","8dd06db9b14503fe","58d7f5f613542cd7","a2cb332a0a9e6630","cd8237db0c02d81b","6b28a6ab48ee0ed0"],"x":14,"y":159,"w":712,"h":242},{"id":"fc63de1623344194","type":"group","z":"69594495cf1ea8a1","name":"Fixed Square Buttons","style":{"label":true},"nodes":["a4a5c7edbcbc8a80","c2a039cfc96615ac","29d24d2d6ac6eb31","29b8f0d5e043f6fe","d83117d229ef6f72","d025498ebe0956be","072064f2e633efe7","d4d7e965819ff4c3","9df29002ae0db5f4","f5376597158c99a7","fc6dd02ed405c4da","811b3fe3f87e27e6","3f51ef2ce012460a","d8fbdc642d84f607"],"x":14,"y":419,"w":712,"h":282},{"id":"bd54913827144c1e","type":"ui-button","z":"69594495cf1ea8a1","g":"d34a0391580f1586","group":"97fe32d54dfd638a","name":"Round 2x2","label":"","order":1,"width":"2","height":"2","emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"round","icon":"power","iconPosition":"left","payload":"","payloadType":"str","topic":"topic","topicType":"msg","buttonColor":"#fff","textColor":"","iconColor":"","x":630,"y":60,"wires":[["722b745215f085f0"]]},{"id":"a4a5c7edbcbc8a80","type":"ui-button","z":"69594495cf1ea8a1","g":"fc63de1623344194","group":"e3b442f221bd875f","name":"Big Square 1","label":"ON","order":1,"width":"2","height":"2","emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"square","icon":"","iconPosition":"left","payload":"","payloadType":"str","topic":"topic","topicType":"msg","buttonColor":"","textColor":"","iconColor":"","x":630,"y":460,"wires":[["c2a039cfc96615ac"]]},{"id":"6eb27320b308af4d","type":"ui-button","z":"69594495cf1ea8a1","g":"d34a0391580f1586","group":"97fe32d54dfd638a","name":"Round 1x1","label":"","order":2,"width":"1","height":"1","emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"smallround","icon":"power","iconPosition":"left","payload":"","payloadType":"str","topic":"topic","topicType":"msg","buttonColor":"#fff","textColor":"","iconColor":"","x":630,"y":100,"wires":[["27ee1b05047db589"]]},{"id":"0b3c7165b87d1ca0","type":"ui-button","z":"69594495cf1ea8a1","g":"d35e14936c5225e4","group":"a8b9bc5ba792cd37","name":"START","label":"START","order":3,"width":"2","height":"1","emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"rounded onehigh","icon":"","iconPosition":"left","payload":"","payloadType":"str","topic":"topic","topicType":"msg","buttonColor":"red","textColor":"black","iconColor":"gold","x":620,"y":280,"wires":[[]]},{"id":"722b745215f085f0","type":"function","z":"69594495cf1ea8a1","g":"d34a0391580f1586","name":"Use msg.class","func":"let state = context.get(\"buttonstate\") || \"on\" \nif (state === \"on\") {\n    state = \"off\"\n    msg.class = \"plainicon\"\n}\nelse {\n    state = \"on\"\n    msg.class = \"redicon\"\n}\ncontext.set (\"buttonstate\", state)\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":360,"y":60,"wires":[["bd54913827144c1e"]]},{"id":"57022ce1f218aad6","type":"ui-button","z":"69594495cf1ea8a1","g":"d35e14936c5225e4","group":"a8b9bc5ba792cd37","name":"Fiat Lux","label":"Fiat Lux","order":1,"width":"4","height":"2","emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"rounded twohigh","icon":"lightbulb-on","iconPosition":"left","payload":"","payloadType":"str","topic":"topic","topicType":"msg","buttonColor":"","textColor":"black","iconColor":"gold","x":620,"y":240,"wires":[["3efcba291e1d4ca7"]]},{"id":"c2a039cfc96615ac","type":"function","z":"69594495cf1ea8a1","g":"fc63de1623344194","name":"ui_update textColor & label","func":"let state = context.get(\"buttonstate\") || \"ON\"\nmsg.ui_update = {}\nif ( state === \"ON\") {\n    state = \"OFF\"\n    msg.ui_update.label = \"OFF\"\n    msg.ui_update.textColor = \"red\";\n}\nelse {\n    state = \"ON\"\n    msg.ui_update.label = \"ON\"\n    msg.ui_update.textColor = \"green\";\n}\nmsg.ui_update.buttonColor = \"white\"\ncontext.set(\"buttonstate\", state)\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":400,"y":460,"wires":[["a4a5c7edbcbc8a80"]]},{"id":"29d24d2d6ac6eb31","type":"ui-button","z":"69594495cf1ea8a1","g":"fc63de1623344194","group":"e3b442f221bd875f","name":"Big Square 2","label":"I/O","order":2,"width":"2","height":"2","emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"square","icon":"","iconPosition":"left","payload":"","payloadType":"str","topic":"topic","topicType":"msg","buttonColor":"","textColor":"","iconColor":"","x":630,"y":500,"wires":[["29b8f0d5e043f6fe"]]},{"id":"29b8f0d5e043f6fe","type":"function","z":"69594495cf1ea8a1","g":"fc63de1623344194","name":"ui_update buttonColor","func":"let state = context.get(\"buttonstate\") || \"ON\"\nmsg.ui_update = {}\nif (state === \"OFF\") {\n    state = \"ON\"\n    msg.ui_update.buttonColor = \"green\"\n}\nelse {\n    state = \"OFF\"\n    msg.ui_update.buttonColor = \"red\"\n}\nmsg.ui_update.textColor = \"black\"\ncontext.set (\"buttonstate\", state)\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":380,"y":500,"wires":[["29d24d2d6ac6eb31"]]},{"id":"d83117d229ef6f72","type":"ui-button","z":"69594495cf1ea8a1","g":"fc63de1623344194","group":"e3b442f221bd875f","name":"Small Square 1","label":"ON","order":3,"width":"1","height":"1","emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"smallsquare","icon":"","iconPosition":"left","payload":"","payloadType":"str","topic":"topic","topicType":"msg","buttonColor":"","textColor":"","iconColor":"","x":620,"y":540,"wires":[["f5376597158c99a7"]]},{"id":"072064f2e633efe7","type":"ui-button","z":"69594495cf1ea8a1","g":"fc63de1623344194","group":"e3b442f221bd875f","name":"Small Square 2","label":"","order":4,"width":"1","height":"1","emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"smallsquare","icon":"","iconPosition":"left","payload":"","payloadType":"str","topic":"topic","topicType":"msg","buttonColor":"","textColor":"","iconColor":"","x":620,"y":580,"wires":[["fc6dd02ed405c4da"]]},{"id":"d4d7e965819ff4c3","type":"ui-button","z":"69594495cf1ea8a1","g":"fc63de1623344194","group":"e3b442f221bd875f","name":"Small Square 3","label":"ON","order":5,"width":"1","height":"1","emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"smallsquare","icon":"","iconPosition":"left","payload":"","payloadType":"str","topic":"topic","topicType":"msg","buttonColor":"","textColor":"","iconColor":"","x":620,"y":620,"wires":[["811b3fe3f87e27e6"]]},{"id":"d025498ebe0956be","type":"ui-button","z":"69594495cf1ea8a1","g":"fc63de1623344194","group":"e3b442f221bd875f","name":"Small Square 4","label":"","order":6,"width":"1","height":"1","emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"smallsquare","icon":"","iconPosition":"left","payload":"","payloadType":"str","topic":"topic","topicType":"msg","buttonColor":"","textColor":"","iconColor":"","x":620,"y":660,"wires":[["3f51ef2ce012460a"]]},{"id":"9df29002ae0db5f4","type":"inject","z":"69594495cf1ea8a1","g":"fc63de1623344194","name":"Init","props":[{"p":"payload"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":110,"y":460,"wires":[["c2a039cfc96615ac","29b8f0d5e043f6fe","f5376597158c99a7","fc6dd02ed405c4da","811b3fe3f87e27e6","3f51ef2ce012460a"]]},{"id":"f5376597158c99a7","type":"function","z":"69594495cf1ea8a1","g":"fc63de1623344194","name":"ui_update textColor & label","func":"let state = context.get(\"buttonstate\") || \"ON\"\nmsg.ui_update = {}\nif (state === \"ON\") {\n    state = \"OFF\"\n    msg.ui_update.label = \"OFF\"\n    msg.ui_update.textColor = \"red\";\n}\nelse {\n    state = \"ON\"\n    msg.ui_update.label = \"ON\"\n    msg.ui_update.textColor = \"green\";\n}\nmsg.ui_update.buttonColor = \"white\"\ncontext.set(\"buttonstate\", state)\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":400,"y":540,"wires":[["d83117d229ef6f72"]]},{"id":"fc6dd02ed405c4da","type":"function","z":"69594495cf1ea8a1","g":"fc63de1623344194","name":"ui_update buttonColor & icon","func":"let color = context.get(\"buttonstate\") || \"ON\"\nmsg.ui_update = {}\nif (color === \"green\") {\n    color = \"red\"\n    msg.ui_update.icon = \"power-off\"\n}\nelse {\n    color = \"green\"\n    msg.ui_update.icon = \"power-on\"\n}\nmsg.ui_update.buttonColor = color \ncontext.set (\"buttonstate\", color)\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":400,"y":580,"wires":[["072064f2e633efe7"]]},{"id":"811b3fe3f87e27e6","type":"function","z":"69594495cf1ea8a1","g":"fc63de1623344194","name":"ui_update everything","func":"let color = context.get(\"buttonstate\") || \"ON\"\nmsg.ui_update = {}\nif (color === \"green\") {\n    msg.ui_update.buttonColor = \"green\" \n    msg.ui_update.textColor = \"red\"\n    msg.ui_update.label = \"ON\"\n    color = \"red\"\n}\nelse {\n    color = \"green\"\n    msg.ui_update.buttonColor = \"red\"\n    msg.ui_update.textColor = \"green\"\n    msg.ui_update.label = \"OFF\"\n}\ncontext.set (\"buttonstate\", color)\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":380,"y":620,"wires":[["d4d7e965819ff4c3"]]},{"id":"3f51ef2ce012460a","type":"function","z":"69594495cf1ea8a1","g":"fc63de1623344194","name":"ui_update icon","func":"let color = context.get(\"buttonstate\") || \"ON\"\nmsg.ui_update = {}\nif (color === \"green\") {\n    msg.ui_update.icon = \"power-off\"\n    color = \"red\"\n}\nelse {\n    color = \"green\"\n    msg.ui_update.icon = \"power-on\"\n}\ncontext.set (\"buttonstate\", color)\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":360,"y":660,"wires":[["d025498ebe0956be"]]},{"id":"3efcba291e1d4ca7","type":"function","z":"69594495cf1ea8a1","g":"d35e14936c5225e4","name":"ui_update iconColor x6","func":"const lightness = [0, 30, 35, 40, 45, 50]\nlet lightlevel = context.get(\"lightlevel\") || 0\nlightlevel = (lightlevel + 1) % 6\nmsg.ui_update = {}\nmsg.ui_update.iconColor = \"hsla(55, 100%, \" + lightness[lightlevel] + \"%, 1)\"\ncontext.set (\"lightlevel\", lightlevel)\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":380,"y":240,"wires":[["57022ce1f218aad6"]]},{"id":"27ee1b05047db589","type":"function","z":"69594495cf1ea8a1","g":"d34a0391580f1586","name":"Use msg.class","func":"let state = context.get(\"buttonstate\") || \"on\" \nif (state === \"on\") {\n    state = \"off\"\n    msg.class = \"plainicon\"\n}\nelse {\n    state = \"on\"\n    msg.class = \"greenicon\"\n}\ncontext.set (\"buttonstate\", state)\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":360,"y":100,"wires":[["6eb27320b308af4d"]]},{"id":"bb86a78e2f17c1b7","type":"ui-button","z":"69594495cf1ea8a1","g":"d35e14936c5225e4","group":"a8b9bc5ba792cd37","name":"Enable","label":"Enable","order":5,"width":"2","height":"1","emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"onehigh","icon":"","iconPosition":"left","payload":"","payloadType":"str","topic":"topic","topicType":"msg","buttonColor":"red","textColor":"black","iconColor":"gold","x":620,"y":320,"wires":[["0a460124e234d3b4"]]},{"id":"0a460124e234d3b4","type":"function","z":"69594495cf1ea8a1","g":"d35e14936c5225e4","name":"class & ui_update label","func":"let state = context.get(\"buttonstate\") || \"ON\"\nlet msg2 = {}\nmsg2.ui_update = {}\nmsg2.ui_update.buttonColor = \"white\"\n\nmsg.ui_update = {}\nif (state === \"ON\") {\n    state = \"OFF\"\n    msg.ui_update.label = \"DISABLED\"\n    msg2.class = \"disabled\"\n}\nelse {\n    state = \"ON\"\n    msg.ui_update.label = \"ENABLED\"\n    msg2.class = \"enabled\"\n}\nmsg.ui_update.buttonColor = \"white\"\nmsg.ui_update.icon = \"\"\ncontext.set(\"buttonstate\", state)\nreturn [msg2, msg];","outputs":2,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":390,"y":280,"wires":[["0b3c7165b87d1ca0"],["bb86a78e2f17c1b7"]]},{"id":"fb769b5b1ac7e460","type":"inject","z":"69594495cf1ea8a1","g":"d34a0391580f1586","name":"Init","props":[{"p":"payload"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":110,"y":60,"wires":[["722b745215f085f0","27ee1b05047db589"]]},{"id":"a2cb332a0a9e6630","type":"function","z":"69594495cf1ea8a1","g":"d35e14936c5225e4","name":"ui_update buttonColor & label","func":"let state = context.get(\"buttonstate\") || \"on\"\nmsg.ui_update = {}\nif (state === \"on\") {\n    state = \"off\"\n    msg.ui_update.buttonColor = \"red\";\n    msg.ui_update.label = \"PORT\"\n}\nelse {\n    state = \"on\"\n    msg.ui_update.buttonColor = \"green\";\n    msg.ui_update.label = \"STARBOARD\"\n}\nmsg.ui_update.textColor = \"black\"\ncontext.set(\"buttonstate\", state)\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":410,"y":360,"wires":[["58d7f5f613542cd7"]]},{"id":"58d7f5f613542cd7","type":"ui-button","z":"69594495cf1ea8a1","g":"d35e14936c5225e4","group":"a8b9bc5ba792cd37","name":"Starboard","label":"Port","order":4,"width":"2","height":"1","emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"onehigh","icon":"","iconPosition":"left","payload":"","payloadType":"str","topic":"topic","topicType":"msg","buttonColor":"","textColor":"","iconColor":"","x":620,"y":360,"wires":[["a2cb332a0a9e6630"]]},{"id":"8dd06db9b14503fe","type":"function","z":"69594495cf1ea8a1","g":"d35e14936c5225e4","name":"ui_update textColor","func":"let state = context.get(\"buttonstate\") || \"on\"\nmsg.ui_update = {}\nif ( state === \"on\") {\n    state = \"off\"\n    msg.ui_update.textColor = \"red\";\n}\nelse {\n    state = \"on\"\n    msg.ui_update.textColor = \"green\";\n}\nmsg.ui_update.buttonColor = \"white\"\ncontext.set(\"buttonstate\", state)\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":200,"wires":[["884f26d74da094c9"]]},{"id":"884f26d74da094c9","type":"ui-button","z":"69594495cf1ea8a1","g":"d35e14936c5225e4","group":"a8b9bc5ba792cd37","name":"Bilge Pump","label":"Bilge Pump","order":2,"width":"4","height":"2","emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"twohigh","icon":"","iconPosition":"left","payload":"","payloadType":"str","topic":"topic","topicType":"msg","buttonColor":"","textColor":"","iconColor":"","x":630,"y":200,"wires":[["8dd06db9b14503fe"]]},{"id":"cd8237db0c02d81b","type":"inject","z":"69594495cf1ea8a1","g":"d35e14936c5225e4","name":"Init","props":[{"p":"payload"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":110,"y":200,"wires":[["8dd06db9b14503fe","3efcba291e1d4ca7","0a460124e234d3b4","a2cb332a0a9e6630"]]},{"id":"00a210647991ac85","type":"ui-template","z":"69594495cf1ea8a1","g":"d34a0391580f1586","page":"dd9e211ef4e39083","name":"CSS: Round","order":0,"width":0,"height":0,"head":"","format":".round button, .smallround button {\n    /* border and shadow on button */\n    border: 0.1vw solid #888888;\n    box-shadow: inset rgba(20, 70, 85, 0.8) 0px 0px 20px -10px;\n}\n.round.plainicon button i, .smallround.plainicon button i{\n    color: whitesmoke !important;\n    text-shadow: -1px -1px 1px #444, 1px -1px 1px #444, -1px 1px 1px #444, 1px 1px 1px #444;\n}\n.round.greenicon button i, .smallround.greenicon button i{\n    color: lime !important;\n    text-shadow: -1px -1px 1px #444, 1px -1px 1px #444, -1px 1px 1px #444, 1px 1px 1px #444, 0px 0px 12px #00ff00;\n}\n.round.redicon button i, .smallround.redicon button i{\n    color: red !important;\n    text-shadow: -1px -1px 1px #444, 1px -1px 1px #444, -1px 1px 1px #444, 1px 1px 1px #444, 0px 0px 12px #f44336;\n}\n.round button {\n    font-size: 3em;\n    border-radius: 50%;\n    max-height: calc( 2 * var(--widget-row-height));\n    min-height: calc( 2 *var(--widget-row-height));\n    max-width: calc( 2 *var(--widget-row-height));\n    min-width: calc( 2 *var(--widget-row-height));\n}\n.smallround button {\n    font-size: 1.5em;\n    border-radius: 50%;\n    max-height: var(--widget-row-height);\n    min-height: var(--widget-row-height);\n    max-width: var(--widget-row-height);\n    min-width: var(--widget-row-height);\n}","storeOutMessages":true,"passthru":false,"resendOnRefresh":true,"templateScope":"page:style","className":"","x":110,"y":100,"wires":[[]]},{"id":"6b28a6ab48ee0ed0","type":"ui-template","z":"69594495cf1ea8a1","g":"d35e14936c5225e4","page":"dd9e211ef4e39083","name":"CSS: Responsive","order":0,"width":0,"height":0,"head":"","format":".onehigh button i, .twohigh button i, .square button i, .smallsquare button i {\n    /* border and shadow on icon */\n    text-shadow: -1px -1px 1px #444, 1px -1px 1px #444, -1px 1px 1px #444, 1px 1px 1px #444, 0px 0px 10px #888888;\n}\n.onehigh button, .twohigh button, .square button, .smallsquare button {\n    /* border and shadow on button */\n    border: 0.1vw solid #888888;\n    box-shadow: inset rgba(20, 70, 85, 0.8) 0px 0px 20px -10px;\n}\n.enabled button {\n    opacity: 1;\n}\n.disabled button {\n    opacity: 0.3;\n}\n.rounded button {\n    border-radius: 5em;\n}\n.onehigh button {\n    font-size: 1em; /* could use vw units but hard to control at minimum resolution */\n    background-color:white;\n    max-height: var(--widget-row-height);   /* in case font size gets out of hand */\n    overflow: hidden;                       /* in case text too wide at this font size */\n}\n.twohigh button {\n    font-size: 2.3em;\n    background-color:white;\n    max-height: calc( 2 * var(--widget-row-height)); /* in case font size gets out of hand */\n    overflow: hidden; /* in case text too wide at this font size */\n}\n","storeOutMessages":true,"passthru":false,"resendOnRefresh":true,"templateScope":"page:style","className":"","x":130,"y":360,"wires":[[]]},{"id":"d8fbdc642d84f607","type":"ui-template","z":"69594495cf1ea8a1","g":"fc63de1623344194","page":"dd9e211ef4e39083","name":"CSS: Square","order":0,"width":0,"height":0,"head":"","format":".square button i, .smallsquare button i {\n    /* border and shadow on icon */\n    text-shadow: -1px -1px 1px #444, 1px -1px 1px #444, -1px 1px 1px #444, 1px 1px 1px #444, 0px 0px 10px #888888;\n}\n.square button, .smallsquare button {\n    /* border and shadow on button */\n    border: 0.1vw solid #888888;\n    box-shadow: inset rgba(20, 70, 85, 0.8) 0px 0px 20px -10px;\n}\n.square button {\n    font-size: 2.5em;\n    max-height: calc( 2 * var(--widget-row-height));\n    min-height: calc( 2 *var(--widget-row-height));\n    max-width: calc( 2 *var(--widget-row-height));\n    min-width: calc( 2 *var(--widget-row-height));\n}\n.smallsquare button {\n    font-size: 1.2em;\n    max-height: var(--widget-row-height);\n    min-height: var(--widget-row-height);\n    max-width: var(--widget-row-height);\n    min-width: var(--widget-row-height);\n}","storeOutMessages":true,"passthru":false,"resendOnRefresh":true,"templateScope":"page:style","className":"","x":110,"y":660,"wires":[[]]},{"id":"97fe32d54dfd638a","type":"ui-group","name":"Fixed Round Buttons","page":"dd9e211ef4e39083","width":"4","height":"1","order":3,"showTitle":true,"className":"","visible":"true","disabled":"false"},{"id":"e3b442f221bd875f","type":"ui-group","name":"Fixed Square Buttons","page":"dd9e211ef4e39083","width":"4","height":"1","order":2,"showTitle":true,"className":"","visible":"true","disabled":"false"},{"id":"a8b9bc5ba792cd37","type":"ui-group","name":"Responsive Buttons","page":"dd9e211ef4e39083","width":"4","height":"1","order":1,"showTitle":true,"className":"","visible":"true","disabled":"false"},{"id":"dd9e211ef4e39083","type":"ui-page","name":"CSS & ui_control Buttons","ui":"ac5e535515ebb9c6","path":"/page2","icon":"home","layout":"grid","theme":"0d92c765bfad87e6","order":2,"className":"","visible":"true","disabled":"false"},{"id":"ac5e535515ebb9c6","type":"ui-base","name":"My Dashboard","path":"/dashboard","includeClientData":true,"acceptsClientConfig":["ui-notification","ui-control"],"showPathInSidebar":false,"navigationStyle":"default"},{"id":"0d92c765bfad87e6","type":"ui-theme","name":"Basic Blue Theme","colors":{"surface":"#4d58ff","primary":"#0094ce","bgPage":"#eeeeee","groupBg":"#ffffff","groupOutline":"#cccccc"},"sizes":{"pagePadding":"12px","groupGap":"12px","groupBorderRadius":"4px","widgetGap":"12px"}}]
6 Likes

We have a feature request (which I've bumped up in priority) to have a layout option for the Switch, which would be similar to the same option on "Text" node

Thank you for sharing that flow, for someone very new to DB2 that is a good example to work from. Most of the css and html stuff goes completely over my head.

1 Like

I hearby reject @jbudd's previous comment that they are not an expert on this topic! I learnt everything I know about using CSS in node-red (Dashboard 1.0) from @jbudd and @hotNipi
Now I'm relearning the topic for Dashboard 2.0.
One thing 1.0 and 2.0 have in common on this subject is how to find out which attributes, like "ui_update.textColor" are available for each chart node. A list, even uncommented, would be awesome. I know from 1.0 that nodes like dropdown have numerous underlying attributes, which are not easy to guess.
Thanks again for these great button examples.

On further investigation, ahem...
The documentation for Dashboard 2.0 already lists the available ui_update parameters for each node. Reading this alongside @jbudd 's examples, and the black magic in the CSS node should get most of us where we need to be.
Dashboard 2.0 Documentation

Hi Jbudd.
I'm a complete beginner. I try and learn.
Can you put pictures of the buttons you use?
Thank you.

In this topic I posted pictures of various buttons.
In your other topic you asked how to use an image as a button and I showed you a way with your chosen image.

Get your flow working with the default dashboard components before you start customising the appearance.

As for the buttons I use, it depends on the purpose of the dashboard.
If I was designing a dashboard to control giant robot dinosaurs I would have a big & shiny red button easily slapped by an excited small child.
If the button was controlling the discharge of raw sewage into Lake Windermere, I would want it to look much more discreet.
Most often though my dashboards are doing less exciting stuff and I generally stick with the default button appearance.

I'm having some trouble changing the button state when an event within the flow changes the state of the item. There seems to be an 'input' to the button but I can't figure out the combination of states to set it to to make the button change on input event.

My goal is a lock/unlock icon but the kicker is that the current state of the lock might be changed via something other than a button press. For instance a timer based lock event at a particular time.

According to the help for the ui-button widget, there are several properties you can change by passing a valid msg.ui_update:

I have an example where the icon changes when the button is pressed - not sure if I included this in the demo.

let state = context.get("buttonstate") || "on" 
if (state === "on") {
    state = "off"
    msg.class = "redicon"
    msg.ui_update = {"icon": "pig"}
}
else {
    state = "on"
    msg.class = "greenicon"
    msg.ui_update = {"icon": "cat"}
}
context.set ("buttonstate", state)
return msg;

NB Looking at it after a couple of months, I would try and avoid using msg.class to change properties that are available via msg.ui_update. I don't know if class greenicon and redicon are really necessary. (It's possible that the node's dynamic styling has been improved since I started playing with it)

It is important to keep your dashboard button in sync with other sources of button actions.
One approach is by passing these actions through the button - there is a check box for this.


But this can very easily result in a runaway loop. I think you need to ensure that any message sent from the function node does not have a msg.payload.

1 Like