Custom Toggle Switch

Is this possible to make in Node-red?

Thank you!

Yes the UI-template node can do what you want to do.
There are numerous examples on the forum

@E1cid, I tried that, but only a checkbox is displayed.

Did you add the css styling too?

Are you referring to this?

<style>
    /*--- Toggle Switch CSS --- */

    /* Settings */
    :root{
        /* Standard Toggle */
        --tog-scale: 1;
        --tog-height: 42px;
        --tog-width: 84px;
        --tog-knob-diameter: 36px;
        --tog-background-inactive: rgb(182, 182, 182);
        --tog-background-active: rgb(127, 180, 210);
        --tog-knob-color-inactive: rgb(130, 130, 130);
        --tog-knob-color-active: rgb(0, 107, 165);
        --tog-text-color-inactive: black;
        --tog-text-color-active: black;
        --tog-text-size: 1rem;
        --tog-transition-speed: 0.15s;
        
        /* Power Toggle */
        --pwr-tog-scale: 1;
        --pwr-tog-height: 42px;
        --pwr-tog-width: 84px;
        --pwr-tog-knob-diameter: 36px;
        --pwr-tog-background-inactive: rgb(182, 182, 182);
        --pwr-tog-background-active: rgb(248, 154, 154);
        --pwr-tog-knob-color-inactive: rgb(130, 130, 130);
        --pwr-tog-knob-color-active: rgb(130, 130, 130); /*rgb(237, 24, 24);*/
        --pwr-tog-knob-icon-color-active: orange;
        --pwr-tog-knob-icon-color-inactive: lightgray;
        --pwr-tog-text-color-inactive: black;
        --pwr-tog-text-color-active: black;
        --pwr-tog-text-size: 1rem;
        --pwr-tog-transition-speed: 0.15s;
    }

    /* CSS Selector for toggle-widget settings */
    .toggle-widget {
        display: block;
        padding: 0;
    }

    /* Standard Toggle switch body */
    .toggle{
        display: block;
        appearance: none;
        -webkit-appearance: none;
        -moz-appearance: none;
        width: var(--tog-width);
        height: var(--tog-height);
        background: var(--tog-background-inactive);
        border-radius: calc(var(--tog-height) / 2);
        position: relative;
        transform: scale(var(--tog-scale));
        transition-property: background;
        transition-duration: var(--tog-transition-speed);
        align-self: center;
        vertical-align: center !important;
        margin: 0px !important;
    }
    
    /* Standard Toggle switch knob */
    .toggle:before{
        content: "";
        background: var(--tog-knob-color-inactive);
        height: var(--tog-knob-diameter);
        width: var(--tog-knob-diameter);
        position: absolute;
        border-radius: 50%;
        top: calc((var(--tog-height) - var(--tog-knob-diameter)) / 2);
        left: calc((var(--tog-height) - var(--tog-knob-diameter)) / 2);
        transition: all var(--tog-transition-speed);
        z-index: 2;
    }
    
    /* Standard Toggle switch inactive text */
    .toggle:after{
        content: "OFF";
        position: absolute;
        font-size: var(--tog-text-size);
        color: var(--tog-text-color-inactive);
        font-weight: bold;
        top: 50%;
        left: 50%;
        transform: translate(8%, -43%);
        z-index: 1;
    }
    
    /* Standard Toggle switch checked state */
    .toggle:checked{
        background: var(--tog-background-active);
    }
    
    /* Standard Toggle Switch Knob offset */
    .toggle:checked::before{
        background: var(--tog-knob-color-active);
        left: calc((var(--tog-height) - var(--tog-knob-diameter)) / 2 + var(--tog-width) - var(--tog-height));
    }
    
    /* Standard Toggle Switch Active Text */
    .toggle:checked::after{
        content: "ON";
        left: 5%;
        color: var(--tog-text-color-active);
    }

    /* --- Power Toggle CSS --- */

    /* Power Toggle switch body */
    .toggle-pwr{
        display: block;
        appearance: none;
        -webkit-appearance: none;
        -moz-appearance: none;
        width: var(--pwr-tog-width);
        height: var(--pwr-tog-height);
        background: var(--pwr-tog-background-inactive);
        border-radius: calc(var(--pwr-tog-height) / 2);
        position: relative;
        transform: scale(var(--pwr-tog-scale));
        transition-property: background;
        transition-duration: var(--pwr-tog-transition-speed);
        align-self: center;
        vertical-align: center !important;
        margin: 0px !important;
    }
    
    /* Power Toggle switch knob */
    .toggle-pwr:before{
        display: flex;
        align-items: center;
        justify-content: center;
        font-family: "Material Icons";
        content: "\e8ac";
        font-size: 2rem;
        color: var(--pwr-tog-knob-icon-color-inactive);
        /* transition: color .35s ease; */
        background: var(--pwr-tog-knob-color-inactive);
        height: var(--pwr-tog-knob-diameter);
        width: var(--pwr-tog-knob-diameter);
        position: absolute;
        border-radius: 50%;
        top: calc((var(--pwr-tog-height) - var(--pwr-tog-knob-diameter)) / 2);
        left: calc((var(--pwr-tog-height) - var(--pwr-tog-knob-diameter)) / 2);
        transition: all var(--pwr-tog-transition-speed);
        z-index: 2;
    }
    
    /* Power Toggle switch inactive text */
    .toggle-pwr:after{
        content: "OFF";
        position: absolute;
        font-size: var(--pwr-tog-text-size);
        color: var(--pwr-tog-text-color-inactive);
        font-weight: bold;
        top: 50%;
        left: 50%;
        transform: translate(8%, -43%);
        z-index: 1;
    }
    
    /* Power Toggle cwitch checked state */
    .toggle-pwr:checked{
        background: var(--pwr-tog-background-active);
    }
    
    /* Power Toggle Switch Knob offset */
    .toggle-pwr:checked::before{
        color: var(--pwr-tog-knob-icon-color-active);
        /*text-shadow: 0 0 3px var(--pwr-tog-knob-icon-color-active);*/
        /*text-shadow: 0 0 2px #fff, 0 0 4px #fff, 0 0 6px #e60073, 0 0 8px #e60073, 0 0 10px #e60073, 0 0 12px #e60073, 0 0 14px #e60073;*/
        text-shadow: 0 0 2px var(--pwr-tog-knob-icon-color-active), 0 0 4px var(--pwr-tog-knob-icon-color-active), 0 0 6px #e60073, 0 0 8px #e60073, 0 0 10px #e60073, 0 0 12px #e60073, 0 0 14px #e60073;
        background: var(--pwr-tog-knob-color-active);
        left: calc((var(--pwr-tog-height) - var(--pwr-tog-knob-diameter)) / 2 + var(--pwr-tog-width) - var(--pwr-tog-height));
    }
    
    /* Power Toggle Switch Active Text */
    .toggle-pwr:checked::after{
        content: "ON";
        left: 5%;
        color: var(--pwr-tog-text-color-active);
    }
</style>

Yes that should be in the template with the html and any Javascript.

It works now, but it makes my dashboard page smaller. How do I fix that?

Template node:

<label class="switch">
    <input type="checkbox">
    <span></span>
</label>

<!-- dribbble -->
<a class="dribbble" href="https://dribbble.com/shots/5449131-Switch-animation"
    target="_blank"><img src="https://cdn.dribbble.com/assets/dribbble-ball-mark-2bd45f09c2fb58dbbfb44766d5d1d07c5a12972d602ef8b32204d28fa3dda554.svg" alt=""></a>


    <style>

        .switch {
        cursor: pointer;
        }
        .switch input {
        display: none;
        }
        .switch input + span {
        width: 48px;
        height: 28px;
        border-radius: 14px;
        transition: all 0.3s ease;
        display: block;
        position: relative;
        background: #FF4651;
        box-shadow: 0 8px 16px -1px rgba(255, 70, 81, 0.2);
        }
        .switch input + span:before, .switch input + span:after {
        content: "";
        display: block;
        position: absolute;
        transition: all 0.3s ease;
        }
        .switch input + span:before {
        top: 5px;
        left: 5px;
        width: 18px;
        height: 18px;
        border-radius: 9px;
        border: 5px solid #fff;
        }
        .switch input + span:after {
        top: 5px;
        left: 32px;
        width: 6px;
        height: 18px;
        border-radius: 40%;
        transform-origin: 50% 50%;
        background: #fff;
        opacity: 0;
        }
        .switch input + span:active {
        transform: scale(0.92);
        }
        .switch input:checked + span {
        background: #48EA8B;
        box-shadow: 0 8px 16px -1px rgba(72, 234, 139, 0.2);
        }
        .switch input:checked + span:before {
        width: 0px;
        border-radius: 3px;
        margin-left: 27px;
        border-width: 3px;
        background: #fff;
        }
        .switch input:checked + span:after {
        -webkit-animation: blobChecked 0.35s linear forwards 0.2s;
        animation: blobChecked 0.35s linear forwards 0.2s;
        }
        .switch input:not(:checked) + span:before {
        -webkit-animation: blob 0.85s linear forwards 0.2s;
        animation: blob 0.85s linear forwards 0.2s;
        }
        
        html {
        -webkit-font-smoothing: antialiased;
        }
        
        * {
        box-sizing: border-box;
        }
        *:before, *:after {
        box-sizing: border-box;
        }
        
        body {
        min-height: 100vh;
        font-family: Roboto, Arial;
        color: #ADAFB6;
        display: flex;
        justify-content: center;
        align-items: center;
        background: #F5F9FF;
        }
        body .dribbble {
        position: fixed;
        display: block;
        right: 20px;
        bottom: 20px;
        }
        body .dribbble img {
        display: block;
        height: 28px;
        }
    </style>

I would say the css of the check box is messing with the css of dashboard. Css is not my thing i can fumble through it but would be guessing. Hopefully some other forum user maybe able to help here.

@E1cid, thank you for the help!

I was able to fix the dashboard size issue.

I am having a new issue. I am using ng-model to send output, but the switch is controlled through injected payload and manually clicking it. The switch does not register the new state when clicked after a state was injected. Any ideas?

Found the solution: setting the ng-checked="checkboxModel = msg.payload". This allowed me to use the toggle smoothly between injected payloads and manual switch control.

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