Building a colour temperature slider that snaps to 100 K steps
A colour temperature control looks like the simplest widget on the screen, one slider and a number next to it, but there are a few small decisions in it that are easy to get wrong. This post goes through the ones we ran into: keeping the value on a fixed grid, keeping it inside its range, labelling it, and drawing a preview colour for it. The examples are plain JavaScript and will work behind any slider component.
Pick the range and the step first
Everything else follows from two choices, the range and the step size. For a screen warmth control, 6500 K is the natural top, because that is the white point most displays are calibrated to. The bottom depends on how far you want to go. In Sundown, the Mac menu bar app we make, the ladder runs from 6500 K down to 500 K in steps of 100 K, so the examples below use those numbers. Change the three constants and the rest still works.
const MIN_K = 500;
const MAX_K = 6500;
const STEP_K = 100;
Snap, then clamp
Raw input arrives in all sorts of shapes: a pointer position turned into a float, a value typed into a box, a number restored from settings saved by an older version. The safest habit is to push every value through one function before you store it or show it.
function snapKelvin(raw) {
const n = Number(raw);
if (Number.isFinite(n) === false) return MAX_K;
const snapped = Math.round(n / STEP_K) * STEP_K;
return Math.min(MAX_K, Math.max(MIN_K, snapped));
}
snapKelvin(2749.9); // 2700
snapKelvin(2750); // 2800
snapKelvin(120); // 500
snapKelvin("abc"); // 6500
The order of the two steps does not change anything while the range limits sit on the grid, as they do here. If you ever move a limit off the grid, though, rounding last can push a value back outside the range, so snapping first and clamping last is the version that stays safe. Falling back to the top of the range for garbage input is a choice, not a rule. We like it because a broken value then shows up as "no warmth" rather than as a deep red screen.
Make the keyboard agree with the pointer
If you use a native range input, set its step to the same constant so that arrow keys move in 100 K steps and the pointer can only land on grid values.
<input type="range" min="500" max="6500" step="100" value="6500" id="warmth">
A custom slider needs the same thing by hand: the arrow keys add or subtract one step and then call snapKelvin, and Page Up or Page Down can move by ten steps.
Label it in kelvin, and say which way is warm
Kelvin runs backwards for most people: the lower the number, the warmer the light. A label like "2700 K" on its own is accurate but does not tell a new user which way to drag. Putting "warmer" at the low end and "cooler" at the high end, or flipping the slider so warmer is to the right, saves a lot of confused dragging. Whatever you do, show the exact number, because that is what people compare.
Drawing a preview swatch
For the swatch next to the slider, Tanner Helland's 2012 blackbody approximation, from his post "How to Convert Temperature (K) to RGB: Algorithm and Sample Code", is a handy shortcut. Keep in mind that his curves were fitted from 1000 K to 40000 K, which is why his sample code clamps any input below 1000 K up to 1000 K. A ladder that goes down to 500 K therefore has a stretch at the bottom where every step returns the same clamped colour, so either accept a flat swatch there or pick your own colours for that part of the range rather than extrapolating the fit.
About
Sundown is a Mac menu bar app made by Jack Richards that warms and dims the display on a schedule. If you want to see where common night modes sit in kelvin, the Blue Light Calculator on our site shows them side by side.
All rights reserved