DEV Community

Mads Stoumann
Mads Stoumann

Posted on • Updated on

Accessible Color Pickers

Most of the Color Pickers I've seen and used, haven't been accessible. They've been touch-friendly, but not keyboard-friendly.

So, I set out to create a Color Picker with range-sliders, which are both touch- and keyboard-friendly (using arrow-keys).

For that, the hsl-format (hue, saturation, lightness) is perfect. "Hue" is the recognisable "rainbow", also often seen as a color wheel.

"Saturation" and "Lightness" are normally "merged" into two overlapping gradients with a single x/y-selector.

Here, they appear as two individual sliders:



I recommend using an <input type="text">, since the value of this type supports any string. <input type="color"> only supports a 7-char hex-code.

The Color Picker can be configured with some options as well:


  • cmyk
  • hex (default)
  • hsl
  • rgb


  • full (default)
  • micro (no alpha-channel, use for <input type="color"> ):


  • mini:


And, if you want to use the trigger (the <input> itself) as preview, the value "update" will hide the preview of the Color Picker:


<input type="text" data-colorpicker="rgb mini">
<input type="text" data-colorpicker="hsl micro update">

Keyboard Shortcuts:


  • ArrowDown : Open ColorPicker.
  • Escape : Close ColorPicker.


  • Arrow Keys : Change value on selected input.
  • Enter : Close ColorPicker, set value.
  • Escape : Close ColorPicker, do not set value.
  • Tab : Go to next element. When tabbing away from last input, the ColorPicker wll close and re-focus on the input/trigger.

And finally, here's a CodePen-demo:

Thanks for reading!

Top comments (3)

supportic profile image
Supportic • Edited

How do you access the values of the sliders when the input changed either via auto update or when clicking ok? Non of my event listeners work. Also maybe as enhancement, when you click outside, do not focus the input anymore. I think you made it that way so you keep the focus after pressing ESC while using keyboard only but the focus is not needed when clicking outside.

const logValue = (e) => {

const main = () => {
  const colorPickers = document.querySelectorAll('[data-colorpicker]');
  colorPickers.forEach((colorPicker) => {
    let pcr = new ColorPicker(colorPicker, colorPicker.dataset);


    colorPicker.addEventListener('input', logValue, false);
    colorPicker.addEventListener('change', logValue, false);
Enter fullscreen mode Exit fullscreen mode
andreacanton profile image
Andrea Canton

What an astonishing work! There is a github/gitlab repo?

madsstoumann profile image
Mads Stoumann

Sure! Its in:
You need the "colorpicker.mjs", "colorlib.mjs" and "range.mjs" from the js-folder, and "c-clp.css" plus "c-rng.css" from the css-folder.