Create Color Picker Using JavaScript

Create Color Picker Using JavaScript
Code Snippet:Color Picker
Author: Dario Corsi
Published: May 1, 2024
Last Updated: May 1, 2024
Downloads: 58
License: MIT
Edit Code online: View on CodePen
Read More

This JavaScript code snippet helps you to create a color picker using the TinyColor library. It allows selecting colors visually and by inputting values. The color picker includes default swatches and adjustable hue and shade spectrums. It updates in real-time.

You can use this code to integrate a color picker into web projects like graphic design tools or image editing apps. It offers a user-friendly interface for selecting and adjusting colors, enhancing the interactivity of your application. Additionally, its lightweight implementation ensures smooth performance on various devices.

How to Create Create Color Picker Using JavaScript

1. First of all, load the Reset CSS and Prefixfree JS by adding the following CDN links into the head tag of your HTML document.

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>

2. Create an HTML structure for the color picker interface. Include elements for displaying selected colors, default swatches, hue spectrum, and shade spectrum.

<div class="color-picker-panel">
  <div class="panel-row">
    <div class="swatches default-swatches"></div>
    <button class="button eyedropper">Get Color</button>
  </div>
  <div class="panel-row">
    <div class="spectrum-map">
      <button id="spectrum-cursor" class="color-cursor"></button>
      <canvas id="spectrum-canvas"></canvas>
    </div>
    <div class="hue-map">
      <button id="hue-cursor" class="color-cursor"></button>
      <canvas id="hue-canvas"></canvas>
    </div>
  </div>
  <div class="panel-row">
    <div id="rgb-fields" class="field-group value-fields rgb-fields active">
      <div class="field-group">
        <label for="" class="field-label">R:</label>
        <input type="number" max="255" min="0" id="red" class="field-input rgb-input"/>
      </div>
      <div class="field-group">
        <label for="" class="field-label">G:</label>
        <input type="number" max="255" min="0" id="green" class="field-input rgb-input"/>
      </div>
      <div class="field-group">
        <label for="" class="field-label">B:</label>
        <input type="number" max="255" min="0" id="blue" class="field-input rgb-input"/>
      </div>
    </div>
    <div id="hex-field" class="field-group value-fields hex-field">
      <label for="" class="field-label">Hex:</label>
      <input type="text" id="hex" class="field-input"/>
    </div>
    <button id="mode-toggle" class="button mode-toggle">Mode</button>
  </div>
  <div class="panel-row">
    <h2 class="panel-header">User Colors</h2>
    <div id="user-swatches" class="swatches custom-swatches">
    </div>
    <button id="add-swatch" class="button add-swatch">
      <span id="color-indicator" class="color-indicator"></span><span>Add to Swatches</span>
    </button>
  </div>
</div>

3. Style the color picker elements using CSS to ensure a visually appealing and user-friendly interface. Customize colors, sizes, and layouts according to your project’s design requirements.

body {
  background: #1F232A;
  font-family: "Proxima Nova", sans-serif;
  color: #8B949A;
  letter-spacing: 0.05em;
  transition: background 0.5s ease;
  min-height: 720px;
}

.color-picker-panel {
  background: #1F232A;
  width: 310px;
  border-radius: 8px;
  border: 2px solid #364347;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

.panel-row {
  position: relative;
  margin: 0 10px 10px;
}
.panel-row:first-child {
  margin-top: 10px;
  margin-bottom: 6px;
}
.panel-row:after {
  content: "";
  display: table;
  clear: both;
}

.panel-header {
  background: #15191C;
  padding: 8px;
  margin: 0 -10px 10px;
  text-align: center;
}

.swatch {
  display: inline-block;
  width: 32px;
  height: 32px;
  background: #ccc;
  border-radius: 4px;
  margin-left: 4px;
  margin-bottom: 4px;
  box-sizing: border-box;
  border: 2px solid #364347;
  cursor: pointer;
}

.default-swatches {
  width: 212px;
}
.default-swatches .swatch:nth-child(6n+1) {
  margin-left: 0;
}

.color-cursor {
  border-radius: 100%;
  background: #ccc;
  box-sizing: border-box;
  position: absolute;
  pointer-events: none;
  z-index: 2;
  border: 2px solid #fff;
  transition: all 0.2s ease;
}
.color-cursor.dragging {
  transition: none;
}
.color-cursor#spectrum-cursor {
  width: 30px;
  height: 30px;
  margin-left: -15px;
  margin-top: -15px;
  top: 0;
  left: 0;
}
.color-cursor#hue-cursor {
  top: 0;
  left: 50%;
  height: 20px;
  width: 20px;
  margin-top: -10px;
  margin-left: -10px;
  pointer-events: none;
}

.spectrum-map {
  position: relative;
  width: 212px;
  height: 200px;
  overflow: hidden;
}

#spectrum-canvas {
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: #ccc;
}

.hue-map {
  position: absolute;
  top: 5px;
  bottom: 5px;
  right: 29px;
  width: 10px;
}

#hue-canvas {
  border-radius: 8px;
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: #ccc;
}

.button {
  background: #2A3137;
  border: 0;
  border-radius: 4px;
  color: #8B949A;
  font-size: 1rem;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
  outline: none;
  cursor: pointer;
  padding: 4px;
}
.button:active {
  background: #262c31;
}
.button.eyedropper {
  position: absolute;
  right: 0;
  top: 0;
  width: 68px;
  height: 68px;
  display: block;
}
.button.add-swatch {
  display: block;
  padding: 6px;
  width: 200px;
  margin: 10px auto 0;
}
.button.mode-toggle {
  position: absolute;
  top: 0;
  right: 0;
  width: 68px;
  height: 40px;
}

.value-fields {
  display: none;
  align-items: center;
}
.value-fields.active {
  display: flex;
}
.value-fields .field-label {
  margin-right: 6px;
}
.value-fields .field-input {
  background: #15191C;
  border: 1px solid #364347;
  box-sizing: border-box;
  border-radius: 2px;
  line-height: 38px;
  padding: 0 4px;
  text-align: center;
  color: #8B949A;
  font-size: 1rem;
  display: block;
}

.rgb-fields .field-group {
  display: flex;
  align-items: center;
}
.rgb-fields .field-input {
  width: 42px;
  margin-right: 10px;
}

.hex-field .field-input {
  width: 170px;
}

.color-indicator {
  display: inline-block;
  vertical-align: middle;
  margin-right: 10px;
  width: 20px;
  height: 20px;
  border-radius: 4px;
  background: #ccc;
}

input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
  /* display: none; <- Crashes Chrome on hover */
  -webkit-appearance: none;
  margin: 0;
  /* <-- Apparently some margin are still there even though it's hidden */
}

4. Now, load the TinyColor JS by adding the following CDN link just before closing the body tag:

<script src='https://cdnjs.cloudflare.com/ajax/libs/tinycolor/1.3.0/tinycolor.min.js'></script>
<script src='https://codepen.io/dariocorsi/pen/aKEBxW/de198bdaf7bb0bf03ac880d82fdfa5d5.js'></script>

5. Finally, add the following JavaScript code to handle color selection and interaction. Use functions to create default swatches, generate hue and shade spectrums, and update selected colors in real-time.

var addSwatch = document.getElementById('add-swatch');
var modeToggle = document.getElementById('mode-toggle');
var swatches = document.getElementsByClassName('default-swatches')[0];
var colorIndicator = document.getElementById('color-indicator');
var userSwatches = document.getElementById('user-swatches');

var bg = document.querySelector(".cd__main");

var spectrumCanvas = document.getElementById('spectrum-canvas');
var spectrumCtx = spectrumCanvas.getContext('2d');
var spectrumCursor = document.getElementById('spectrum-cursor'); 
var spectrumRect = spectrumCanvas.getBoundingClientRect();

var hueCanvas = document.getElementById('hue-canvas');
var hueCtx = hueCanvas.getContext('2d');
var hueCursor = document.getElementById('hue-cursor'); 
var hueRect = hueCanvas.getBoundingClientRect();

var currentColor = '';
var hue = 0;
var saturation = 1;
var lightness = .5;

var rgbFields = document.getElementById('rgb-fields');
var hexField = document.getElementById('hex-field');

var red = document.getElementById('red');
var blue = document.getElementById('blue');
var green = document.getElementById('green');
var hex = document.getElementById('hex'); 

function ColorPicker(){
  this.addDefaultSwatches();
  createShadeSpectrum();
  createHueSpectrum();
};

ColorPicker.prototype.defaultSwatches = [
  '#FFFFFF', 
  '#FFFB0D', 
  '#0532FF', 
  '#FF9300', 
  '#00F91A', 
  '#FF2700', 
  '#000000', 
  '#686868', 
  '#EE5464', 
  '#D27AEE', 
  '#5BA8C4', 
  '#E64AA9'
];

function createSwatch(target, color){
  var swatch = document.createElement('button');
  swatch.classList.add('swatch');
  swatch.setAttribute('title', color);
  swatch.style.backgroundColor = color;
  swatch.addEventListener('click', function(){
    var color = tinycolor(this.style.backgroundColor);     
    colorToPos(color);
    setColorValues(color);
  });
  target.appendChild(swatch);
  refreshElementRects();
};

ColorPicker.prototype.addDefaultSwatches = function() {
  for(var i = 0; i < this.defaultSwatches.length; ++i){
    createSwatch(swatches, this.defaultSwatches[i]);
  } 
}

function refreshElementRects(){
  spectrumRect = spectrumCanvas.getBoundingClientRect();
  hueRect = hueCanvas.getBoundingClientRect();
}

function createShadeSpectrum(color) {
  canvas = spectrumCanvas;
  ctx = spectrumCtx;
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  if(!color) color = '#f00';
  ctx.fillStyle = color;
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  var whiteGradient = ctx.createLinearGradient(0, 0, canvas.width, 0);
  whiteGradient.addColorStop(0, "#fff");
  whiteGradient.addColorStop(1, "transparent");
  ctx.fillStyle = whiteGradient;
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  var blackGradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
  blackGradient.addColorStop(0, "transparent");
  blackGradient.addColorStop(1, "#000");
  ctx.fillStyle = blackGradient;
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  canvas.addEventListener('mousedown', function(e){
    startGetSpectrumColor(e);
  });
};

function createHueSpectrum() {
  var canvas = hueCanvas;
  var ctx = hueCtx;
  var hueGradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
  hueGradient.addColorStop(0.00, "hsl(0,100%,50%)");
  hueGradient.addColorStop(0.17, "hsl(298.8, 100%, 50%)");
  hueGradient.addColorStop(0.33, "hsl(241.2, 100%, 50%)");
  hueGradient.addColorStop(0.50, "hsl(180, 100%, 50%)");
  hueGradient.addColorStop(0.67, "hsl(118.8, 100%, 50%)");
  hueGradient.addColorStop(0.83, "hsl(61.2,100%,50%)");
  hueGradient.addColorStop(1.00, "hsl(360,100%,50%)");
  ctx.fillStyle = hueGradient;
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  canvas.addEventListener('mousedown', function(e){
    startGetHueColor(e);
  });
};

function colorToHue(color){
  var color = tinycolor(color);
  var hueString = tinycolor('hsl '+ color.toHsl().h + ' 1 .5').toHslString();
  return hueString;
};

function colorToPos(color){
  var color = tinycolor(color);
  var hsl = color.toHsl();
  hue = hsl.h;
  var hsv = color.toHsv();
  var x = spectrumRect.width * hsv.s;
  var y = spectrumRect.height * (1 - hsv.v);
  var hueY = hueRect.height - ((hue / 360) * hueRect.height);
  updateSpectrumCursor(x,y);
  updateHueCursor(hueY);
  setCurrentColor(color);
  createShadeSpectrum(colorToHue(color));   
};

function setColorValues(color){  
  //convert to tinycolor object
  var color = tinycolor(color);
  var rgbValues = color.toRgb();
  var hexValue = color.toHex();
  //set inputs
  red.value = rgbValues.r;
  green.value = rgbValues.g;
  blue.value = rgbValues.b;
  hex.value = hexValue;
};

function setCurrentColor(color){
  color = tinycolor(color);
  currentColor = color;
  colorIndicator.style.backgroundColor = color;
//  document.body.style.backgroundColor = color; 
  bg.style.backgroundColor = color; 
  spectrumCursor.style.backgroundColor = color; 
  hueCursor.style.backgroundColor = 'hsl('+ color.toHsl().h +', 100%, 50%)';
};

function updateHueCursor(y){
  hueCursor.style.top = y + 'px';
}

function updateSpectrumCursor(x, y){
  //assign position
  spectrumCursor.style.left = x + 'px';
  spectrumCursor.style.top = y + 'px';  
};

var startGetSpectrumColor = function(e) {
  getSpectrumColor(e);
  spectrumCursor.classList.add('dragging');
  window.addEventListener('mousemove', getSpectrumColor);
  window.addEventListener('mouseup', endGetSpectrumColor);
};

function getSpectrumColor(e) {
  // got some help here - http://stackoverflow.com/questions/23520909/get-hsl-value-given-x-y-and-hue
  e.preventDefault();
  //get x/y coordinates
  var x = e.pageX - spectrumRect.left;
  var y = e.pageY - spectrumRect.top;
  //constrain x max
  if(x > spectrumRect.width){ x = spectrumRect.width}
  if(x < 0){ x = 0}
  if(y > spectrumRect.height){ y = spectrumRect.height}
  if(y < 0){ y = .1}  
  //convert between hsv and hsl
  var xRatio = x / spectrumRect.width * 100;
  var yRatio = y / spectrumRect.height * 100; 
  var hsvValue = 1 - (yRatio / 100);
  var hsvSaturation = xRatio / 100;
  lightness = (hsvValue / 2) * (2 - hsvSaturation);
  saturation = (hsvValue * hsvSaturation) / (1 - Math.abs(2 * lightness - 1));
  var color = tinycolor('hsl ' + hue + ' ' + saturation + ' ' + lightness);
  setCurrentColor(color);  
  setColorValues(color);
  updateSpectrumCursor(x,y);
};

function endGetSpectrumColor(e){
  spectrumCursor.classList.remove('dragging');
  window.removeEventListener('mousemove', getSpectrumColor);
};

function startGetHueColor(e) {
  getHueColor(e);
  hueCursor.classList.add('dragging');
  window.addEventListener('mousemove', getHueColor);
  window.addEventListener('mouseup', endGetHueColor);
};

function getHueColor(e){
  e.preventDefault();
  var y = e.pageY - hueRect.top;
  if (y > hueRect.height){ y = hueRect.height};
  if (y < 0){ y = 0};  
  var percent = y / hueRect.height;
  hue = 360 - (360 * percent);
  var hueColor = tinycolor('hsl '+ hue + ' 1 .5').toHslString();
  var color = tinycolor('hsl '+ hue + ' ' + saturation + ' ' + lightness).toHslString();
  createShadeSpectrum(hueColor);
  updateHueCursor(y, hueColor)
  setCurrentColor(color);
  setColorValues(color);
};

function endGetHueColor(e){
    hueCursor.classList.remove('dragging');
  window.removeEventListener('mousemove', getHueColor);
};

// Add event listeners

red.addEventListener('change', function(){
    var color = tinycolor('rgb ' + red.value + ' ' + green.value + ' ' + blue.value );
    colorToPos(color);
});

green.addEventListener('change', function(){
    var color = tinycolor('rgb ' + red.value + ' ' + green.value + ' ' + blue.value );
    colorToPos(color);
});

blue.addEventListener('change', function(){
    var color = tinycolor('rgb ' + red.value + ' ' + green.value + ' ' + blue.value );
    colorToPos(color);
});

addSwatch.addEventListener('click', function(){  
  createSwatch(userSwatches, currentColor);
});

modeToggle.addEventListener('click', function(){
  if(rgbFields.classList.contains('active') ? rgbFields.classList.remove('active') : rgbFields.classList.add('active'));
  if(hexField.classList.contains('active') ? hexField.classList.remove('active') : hexField.classList.add('active'));
});

window.addEventListener('resize', function(){
  refreshElementRects();
});

new ColorPicker();

That’s all! hopefully, you have successfully created Create Color Picker Using Javascript. If you have any questions or suggestions, feel free to comment below.

Leave a Comment