0

Simple and easy to use vanilla JavaScript color picker

This simple color picker component you can use without any additional dependencies.

console.clear();
function $(selector) { return document.querySelector(selector); }


        
/* Basic example */

const parentBasic = $('#basic'),
      popupBasic = new Picker(parentBasic);
popupBasic.onChange = function(color) {
    parentBasic.style.backgroundColor = color.rgbaString;
};
//Open the popup manually:
popupBasic.openHandler();



/* More options */

const parentCustom = $('#custom'),
      popupCustom = new Picker({
          parent: parentCustom,
          popup: 'top',
          color: 'violet',
          //alpha: false,
          //editor: false,
          editorFormat: 'rgb',
          onDone: function(color) {
              parentCustom.style.backgroundColor = color.rgbaString;
          },
      });



/* Shared picker */

const parentShared = $('#shared'),
      parentBG = $('#color-bg'),
      popupShared = new Picker({
          popup: 'top',
          onChange: function(color) {
              this.settings.parent.setAttribute('data-color', color.rgbaString);
              updateBackground();
          }
      });

//Picker switching:
parentShared.addEventListener('click', function(e) {
    if(e.target.nodeName !== 'A') { return; }
    e.preventDefault();
    const parent = e.target;

    popupShared.movePopup({
        parent: parent,
        color: parent.getAttribute('data-color'),
        //Future feature...
        //alpha: (parent !== parentBG),
    }, true);
});

//Color handling:
function updateBackground() {
    function updateElement(elm) {
        const color = elm.style.color = elm.getAttribute('data-color');
        return color;
    }

    const body = document.body,
          c1 = updateElement($('#color-line1')),
          c2 = updateElement($('#color-line2')),
          patternSize = 200,
          pattern = `repeating-linear-gradient( 0deg, transparent 0, transparent ${patternSize * .6}px, ${c2} 0, ${c2} ${patternSize * .8}px, transparent 0, transparent ${patternSize}px),
                     repeating-linear-gradient(90deg, transparent 0, transparent ${patternSize * .6}px, ${c2} 0, ${c2} ${patternSize * .8}px, transparent 0, transparent ${patternSize}px),
                     repeating-linear-gradient( 0deg, ${c1} 0, ${c1} ${patternSize * .4}px, transparent 0, transparent ${patternSize}px),
                     repeating-linear-gradient(90deg, ${c1} 0, ${c1} ${patternSize * .4}px, transparent 0, transparent ${patternSize}px)`;

    parentShared.style.backgroundColor = updateElement(parentBG);
    parentShared.style.backgroundImage = pattern;
}
updateBackground();



/* Fixed picker */

const parentFixed = $('#fixed'),
      pickerFixed = new Picker({
          parent: parentFixed,
          popup: false,
          alpha: false,
          editor: false,
          color: 'orangered',
          onChange: function(color) {
              parentFixed.style.backgroundColor = color.rgbaString;
          },
      });
//Set the color silently (doesn't trigger .onChange()):
pickerFixed.setColor('lime', true);



/* Disable normal link navigation */

[parentBasic, parentCustom].forEach(p => {
    p.addEventListener('click', function(e) {
        e.preventDefault();
    });
})
<section>
    <h2>Basic example</h2>
    <a href="#" class="button" id="basic">Click me!</a>
</section>

<section>
    <h2>More <a href="https://vanilla-picker.js.org/gen/Picker.html#setOptions__anchor" target="_blank">options</a></h2>
    <a href="#" class="button" id="custom">Click me (and then 'Ok')!</a>
</section>

<section id="shared">
    <h2>Shared picker</h2>
    <p>Select background colors:</p>
    <div class="pickers">
        <a href="#" class="button picker_sample" id="color-bg"    data-color="white"></a>
        <a href="#" class="button picker_sample" id="color-line1" data-color="rgba(30,144,255, 0.2)"></a>
        <a href="#" class="button picker_sample" id="color-line2" data-color="rgba(255,99,71, 0.3)"></a>
    </div>
</section>

<section>
    <h2>Fixed (non-popup) picker</h2>
    <div id="fixed"></div>
</section>
body {
    display: flex;
    flex-flow: column nowrap;
    min-height: 100vh;
    margin: 0;
    align-items: center;

    font-family: Georgia, sans-serif;
    font-size: 18px;
    //background: radial-gradient(honeydew, lightgreen);
    background-color: lightgreen;
}
h1 {
    align-self: stretch;
    margin: 0;
    padding: 1em 0;
    text-align: center;
    background: rgba(white, .8);
}
h2 {
    margin-top: 0;
    font-size: 1.3em;
}
section {
    width: 100%;
    max-width: 500px;
    margin-top: 3em;
    padding: 1em;
    border: 1em solid transparent;
    box-sizing: border-box;
    background: rgba(white, .7);
    background-clip: padding-box;
    
    &::last-of-type {
        margin-bottom: 1em;
    }
}

.button {
    position: relative;
    display: inline-block;
    box-sizing: border-box;
    padding: .5em 1em;
    min-height: 2em;
    border: none;
    outline: none;
    overflow: visible;
    
    background-color: dodgerblue;
    color: white;

    font-family: sans-serif;
    text-align: center;
    cursor: pointer;
    
    &:hover {
        //background-image: linear-gradient(white, transparent);
    }
    &:focus {
        outline: .3em dashed orange;
    }
}

#custom {
    .picker_editor {
        width: 100%;
    }
}

#shared {
    h2 {
        margin-bottom: 2em;
    }
    .pickers {
        display: inline-flex;
        padding: .5em;
        background-color: gainsboro;
        border: 1px solid silver;

        .button {
            background-color: white;
            &:not(:last-child) {
                margin-right: .5em;
            }

            &::before {
                top:0; left:0;
            }
        }
    }
}

#fixed {
    display: table;
    padding: 1em;
    border: 1px solid silver
}

@media(max-width: 400px) {
    .picker_wrapper.popup {
        font-size: 2vw !important;
    }
}
RUN
add comment
Suggest a different solution or add another example