JSFiddle - React, Tailwind, and code Playground

HTML

<div id="p3" class="swatch"><span></span></div>
<div id="srgb" class="swatch"><span></span></div>

<div class="slidecontainer">
  red:
  <input type="range" min="0" max="1" value="1" step="0.01" class="slider" id="redrange">
  <span id="redlabel"></span>
</div>
<div class="slidecontainer">
  green:
  <input type="range" min="0" max="1" value="0.22" step="0.01" class="slider" id="greenrange">
  <span id="greenlabel"></span>
</div>
<div class="slidecontainer">
  blue:
  <input type="range" min="0" max="1" value="0" step="0.01" class="slider" id="bluerange">
  <span id="bluelabel"></span>
</div>
<h3>HSL:</h3> <p id="hsl"></p>
<h3>HWB:</h3> <p id="hwb"></p>

CSS

.swatch {
    width: 400px;
    height: 50px;
    border:1px solid black;
  }
  span {
    padding: 10px;
  }

JavaScript

const p3 = document.getElementById("p3");
const srgb = document.getElementById("srgb");
const hslLabel = document.getElementById("hsl");
const hwbLabel = document.getElementById("hwb");

sliders = {};
for (channel of ["red", "green", "blue"])  {
  const slider = {};
  sliders[channel] = slider;
  slider.range = document.getElementById(`${channel}range`);
  slider.label = document.getElementById(`${channel}label`);
  slider.label.innerHTML = slider.range.value;

  // Update the current slider value (each time you drag the slider handle)
  slider.range.oninput = function() {
    updateColor();
    slider.label.innerHTML = this.value;
  }
}

function updateColor() {
  const red = sliders["red"].range.value;
  const green = sliders["green"].range.value;
  const blue = sliders["blue"].range.value;
  const color = `color(display-p3 ${red} ${green} ${blue})`;
  p3.style.backgroundColor = color;
  p3.children[0].innerHTML = color;

  srgb.style.backgroundColor = `color-mix(in srgb, ${color} 100%, black)`;
  srgblabel = getComputedStyle(srgb)["backgroundColor"];
  srgb.children[0].innerHTML = srgblabel;

  const srgbChannels = srgblabel.split(" ");
  const rgb = [parseFloat(srgbChannels[1]), parseFloat(srgbChannels[2]), parseFloat(srgbChannels[3])];

  const hsl = rgbToHsl(rgb[0], rgb[1], rgb[2]);
  const hslRoundTripSRGB = hslToRgb(hsl[0], hsl[1], hsl[2]);

  hslLabel.innerText = `H: ${Math.round(hsl[0])} degrees\nS: ${Math.round(hsl[1])}%\nL: ${Math.round(hsl[2])}%

  Roundtripping to srgb:
  ${hslRoundTripSRGB}

  Differences by channel:
  red: ${rgb[0] - hslRoundTripSRGB[0]}
  green: ${rgb[1] - hslRoundTripSRGB[1]}
  blue: ${rgb[2] - hslRoundTripSRGB[2]}
  `;

  const hwb = rgbToHwb(rgb[0], rgb[1], rgb[2]);
  const hwbRoundTripSRGB = hwbToRgb(hwb[0], hwb[1], hwb[2]);

  hwbLabel.innerText = `H: ${Math.round(hwb[0])} degrees\nW: ${Math.round(hwb[1])}%\nB: ${Math.round(hwb[2])}%

  Roundtripping to srgb:
  ${hwbRoundTripSRGB}

  Differences by channel:
  red: ${rgb[0] -...