javascript 50 lines · 7 steps

A validated color picker in React

Two uncontrolled inputs share one committed color, validated and synced through a single commit function.

Explained by highlit
1import { useCallback, useRef, useState } from 'react';
2 
3export function ColorPicker({ initialColor = '#3b82f6', onCommit }) {
4 const [committed, setCommitted] = useState(initialColor);
5 const swatchRef = useRef(null);
6 const hexRef = useRef(null);
7 
8 const normalize = (value) => {
9 const trimmed = value.trim().replace(/^#?/, '#').toLowerCase();
10 return /^#[0-9a-f]{6}$/.test(trimmed) ? trimmed : null;
11 };
12 
13 const commit = useCallback(
14 (raw) => {
15 const next = normalize(raw);
16 if (!next || next === committed) {
17 if (hexRef.current) hexRef.current.value = committed;
18 return;
19 }
20 setCommitted(next);
21 if (swatchRef.current) swatchRef.current.value = next;
22 if (hexRef.current) hexRef.current.value = next;
23 onCommit?.(next);
24 },
25 [committed, onCommit],
26 );
27 
28 return (
29 <div className="color-picker">
30 <input
31 ref={swatchRef}
32 type="color"
33 aria-label="Pick color"
34 defaultValue={committed}
35 onBlur={(e) => commit(e.target.value)}
36 />
37 <input
38 ref={hexRef}
39 type="text"
40 inputMode="text"
41 spellCheck={false}
42 maxLength={7}
43 defaultValue={committed}
44 onBlur={(e) => commit(e.target.value)}
45 onKeyDown={(e) => e.key === 'Enter' && e.currentTarget.blur()}
46 />
47 <span className="color-picker__preview" style={{ backgroundColor: committed }} />
48 </div>
49 );
50}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Uncontrolled inputs with refs let you validate on commit rather than re-rendering on every keystroke.
  2. 2A single normalize-and-commit path keeps multiple inputs and derived UI in sync from one source of truth.
  3. 3Rejecting invalid or unchanged input by resetting the field's value gives users immediate, honest feedback.

Related explainers

Share this explainer

Here's the card — post it anywhere.

A validated color picker in React — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code