JSFiddle - React, Tailwind, and code Playground

by Josh Pullen

HTML

<div class="colorPicker">
  <div class="colorPicker-palette">
    <div class="colorPicker-palette-pointer"></div>
  </div>
  <div class="colorPicker-hue">
    <div class="colorPicker-hue-pointer"></div>
  </div>
  <div class="colorPicker-alpha">
    <div class="colorPicker-alpha-backgroundColor"></div>
    <div class="colorPicker-alpha-pointer"></div>
  </div>
</div>

CSS

.colorPicker {
  display: inline-flex;
  padding: 10px;
  background: #fff;
  border: 1px solid rgba(0,0,0,0.2);
  border-radius: 2px;
}
.colorPicker-palette {
  background: #f00;
  width: 200px;
  height: 200px;
  position: relative;
  margin-right: 10px;
  box-shadow: 0 0 0 1px rgba(0,0,0,0.2);
  border-radius: 2px;
}
.colorPicker-palette::before,
.colorPicker-palette::after {
  display: block;
  content: ' ';
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  border-radius: 2px;
}
.colorPicker-palette::before {
  background: linear-gradient(to right, #fff 0%, rgba(255,255,255,0) 100%);
}
.colorPicker-palette::after {
  background: linear-gradient(to bottom, transparent 0%, #000 100%);
}
.colorPicker-hue {
  width: 20px;
  height: 200px;
  margin-right: 10px;
  position: relative;
  background: linear-gradient(to bottom, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
  box-shadow: 0 0 0 1px rgba(0,0,0,0.2);
  border-radius: 2px;
}
.colorPicker-alpha {
  width: 20px;
  height: 200px;
  position: relative;
  background: linear-gradient(45deg, #aaa 25%, transparent 25%, transparent 75%, #aaa 75%, #aaa), 
linear-gradient(45deg, #aaa 25%, transparent 25%, transparent 75%, #aaa 75%, #aaa);
  background-size: 10px 10px;
  background-position: 0 0, 5px 5px;
  box-shadow: 0 0 0 1px rgba(0,0,0,0.2);
  border-radius: 2px;
}
.colorPicker-alpha-backgroundColor {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  background: linear-gradient(to bottom, #f00 0%, rgba(255, 0, 0, 0) 100%);
  border-radius: 2px;
}

/* Pointers */
.colorPicker-palette-pointer {
  width: 8px;
  height: 8px;
  transform: translate(-50%, -50%);
  border-radius: 999px;
  border: 1px solid #000;
  box-shadow: 0 0 0 1px #fff;
  position: absolute;
  z-index: 80;
}
.colorPicker-hue-pointer,
.colorPicker-alpha-pointer {
  width: 22px;
  height: 3px;
  transform: translate(-50%, -50%);
  border-radius: 2px;
  border: 1px...

JavaScript

let colorPicker = document.querySelector('.colorPicker');
let colorPickerPalette = document.querySelector('.colorPicker-palette');
let colorPickerPalettePointer = document.querySelector('.colorPicker-palette-pointer');

let hue = 0;
let shade = 0;
let lightness = 0;
let alpha = 1;

let paletteMouseDown = false;
colorPickerPalette.addEventListener('mousedown', function() {
	paletteMouseDown = true;
});
window.addEventListener('mouseup', function() {
	paletteMouseDown = false;
});
function updatePalettePointer(e, force) {
  if(paletteMouseDown || force) {
    let bounds = colorPickerPalette.getBoundingClientRect();
    let x = e.clientX - bounds.left;
    let y = e.clientY - bounds.top;
    x = Math.min(200, Math.max(0, x));
    y = Math.min(200, Math.max(0, y));
    colorPickerPalettePointer.style.top = y + 'px';
    colorPickerPalettePointer.style.left = x + 'px';
  }
}
window.addEventListener('mousemove', updatePalettePointer);
colorPickerPalette.addEventListener('click', function(e){ updatePalettePointer(e, true); });



let colorPickerHue = document.querySelector('.colorPicker-hue');
let colorPickerHuePointer = document.querySelector('.colorPicker-hue-pointer');

let hueMouseDown = false;
colorPickerHue.addEventListener('mousedown', function() {
	hueMouseDown = true;
});
window.addEventListener('mouseup', function() {
	hueMouseDown = false;
});
function updateHuePointer(e, force) {
  if(hueMouseDown || force) {
    let bounds = colorPickerHue.getBoundingClientRect();
    let y = e.clientY - bounds.top;
    y = Math.min(200, Math.max(0, y));
    hue = y / colorPickerHue.offsetHeight * 360;
    colorPickerPalette.style.background = 'hsl(' + hue + ', 100%, 50%)';
    colorPickerHuePointer.style.top = y + 'px';
  }
}
window.addEventListener('mousemove', updateHuePointer);
colorPickerHue.addEventListener('click', function(e){ updateHuePointer(e, true); });



let colorPickerAlpha = document.querySelector('.colorPicker-alpha');
let colorPickerAlphaPointer =...