Back

Color Swatch

easy

Streak

0 days

Progress

0%

Submitted

0

Color Swatch

React30 mineasyFreeNew

Prompt

A Color Swatch lets users pick a color from a preset palette or type a custom hex value. It's a staple in design-tool and component-library interviews because it exercises controlled inputs, two-way synchronization, and input validation — all at once.

Build a <ColorSwatch> that shows a 12-color preset grid and a hex input field. Clicking a swatch selects it and fills the input. Typing in the input updates the swatch (and a live preview panel) only when the entered value is a valid 3 or 6-digit hex color. The input must allow partial typing without resetting.

The key insight is separating the committed color (drives the preview) from the draft input value (what the user is typing). These must be kept as two independent pieces of state that sync only on valid hex.

Requirements

  • →Display a grid of at least 12 preset color swatches
  • →Clicking a swatch selects it and updates the hex input
  • →Hex input updates the preview only on valid #RGB or #RRGGBB
  • →Input must allow partial typing without resetting cursor
  • →Show visual invalid state on the input for bad hex
  • →Selected swatch highlighted with a visible ring indicator
Example
Loading preview...
For the best coding experience, we recommend using a desktop device.
Preparing Sandbox...
Premium interview report

What interviewers score in this build

Use this before reading the code. It tells you what to say, what to test, and where machine-coding candidates usually lose points.

Interview signals

  • Two-state separation: inputValue (draft) and selectedColor (applied) are independent
  • Hex validation: Regex validates #RGB and #RRGGBB before applying
  • Two-way sync: Swatch click updates input; valid input updates swatch
  • Selected ring indicator: Box-shadow double-ring on selected swatch

Time checkpoints

  1. 1

    0–3 min: Explain two-state approach and why single state breaks UX

  2. 2

    3–7 min: Render preset grid with click handler and selected ring

  3. 3

    7–12 min: Wire controlled hex input with two-state logic

  4. 4

    12–16 min: Add hex validation regex and error styling

Edge-case checklist

Empty data and first-load state
Slow network, failed request, and retry path
Keyboard navigation and focus movement
Large input size, re-render pressure, and cleanup

Common mistakes

  • Starting with JSX before naming state and events.
  • Ignoring accessibility until the final minute.
  • Over-building abstractions instead of finishing the required behavior.
  • Failing to narrate trade-offs while coding.
SolutionRead-only · Live Preview

Technical Explanation

Why This Question Exists

Color Swatch tests controlled input synchronisation — one of the most common sources of bugs in form-heavy applications. The challenge is keeping two input sources (click vs type) in sync without breaking either one's UX. Candidates who use a single state variable and reset on invalid input will have an input that fights the user's cursor position.

The Wrong Approach: Single State

// ❌ WRONG — resets input mid-type, fighting cursor position
const [color, setColor] = useState('#3b82f6');

const onType = (e) => {
  const v = e.target.value;
  if (isValidHex(v)) {
    setColor(v); // only updates on valid — input resets on every invalid keystroke
  }
};

When the user types '#3b8' (invalid mid-type), setColor doesn't update, so React re-renders the input with the old valid value. The cursor jumps to the end. The user can't type freely.

The Right Approach: Two-State Separation

// ✅ CORRECT — draft input vs committed color
const [selected, setSelected] = useState('#3b82f6'); // applied color
const [inputVal, setInputVal] = useState('#3b82f6'); // what's in the field

const onType = (e) => {
  const v = e.target.value;
  setInputVal(v);                  // always update — never fight the cursor
  if (isValidHex(v)) setSelected(v); // only apply when valid
};

const pickSwatch = (hex) => {
  setSelected(hex);  // both sync on swatch click
  setInputVal(hex);
};

This is the same pattern used by React Hook Form, Formik, and every production form library: maintain a "draft" value in the field independently of the "committed" model value.

ℹ Interview Tip

Say: "I separate the committed color from the draft input value. This is the controlled input pattern used by every major form library — the field owns its own draft, validation runs against it, and only a passing value propagates to the model."

Hex Validation

const isValidHex = (v) => /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(v);

The regex covers both shorthand (#RGB, e.g. #f00) and full (#RRGGBB, e.g. #ff0000). The ^ and $ anchors ensure no extra characters are accepted. The alternation | handles both lengths.

Selected Swatch Ring — CSS Trick

/* Double box-shadow creates gap + ring without extra markup */
.swatch.selected {
  box-shadow:
    0 0 0 2px #0f172a,   /* matches page background — creates gap */
    0 0 0 4px #f8fafc;   /* visible white ring */
}

The first shadow is the same color as the page background — it creates a visual gap between the swatch and the ring. The second shadow is the actual ring. No extra wrapper element needed. This works on any swatch color because the gap always matches the page background.

Normalising Hex for Comparison

// Shorthand #RGB !== full #RRGGBB even for same color
// '#f00' !== '#ff0000' — use a consistent format for comparison
const normalise = (hex) => {
  if (/^#[0-9a-fA-F]{3}$/.test(hex)) {
    return '#' + hex[1]+hex[1]+hex[2]+hex[2]+hex[3]+hex[3];
  }
  return hex.toLowerCase();
};

If you store presets in full format but the user types shorthand, the swatch won't highlight. Normalise both to the same format before comparing, or store presets in the format you expect.

⚠ Common Pitfall: Not clamping maxLength

Without maxLength={7} on the input, a user can type arbitrarily long strings. Your regex will reject them, but the UX is confusing. Always constrain the input to the maximum valid length (#RRGGBB = 7 chars).

Interview Criteria

Two-state separation

inputValue (draft) and selectedColor (applied) are independent

Hex validation

Regex validates #RGB and #RRGGBB before applying

Two-way sync

Swatch click updates input; valid input updates swatch

Selected ring indicator

Box-shadow double-ring on selected swatch

Input UX

Error styling on invalid hex, no cursor-fighting

Time Checkpoints

0–3 min

0–3 min: Explain two-state approach and why single state breaks UX

3–7 min

3–7 min: Render preset grid with click handler and selected ring

7–12 min

7–12 min: Wire controlled hex input with two-state logic

12–16 min

12–16 min: Add hex validation regex and error styling

16–20 min

16–20 min: Add live preview panel and color-dot in input row

20–25 min

20–25 min: Test all edge cases: partial typing, shorthand hex, reset

Streak

0 days

Last active: Sign in to track

Progress

0%

0/0 solved

Submitted

0

Solutions pushed to review history.