react-colorful
react-colorful is a controlled color-picker component set for React and Preact. It exports pickers for HEX, RGB, HSL, HSV, alpha-bearing variants, and string or object value shapes, plus a separate HEX text input. Version 5.8 adds onChangeEnd for persistence or undo checkpoints and injects its base styles into the nearest document or ShadowRoot. The package has no runtime dependencies, includes TypeScript declarations, and leaves popovers, swatches, labels, validation messages, and form integration to your application.
A strong low-level color control when size, value-shape choice, and composition matter. Skip it if you expect a polished popover field out of the box, because most product UI around the picker is intentionally yours.
Use it if
- You want a small controlled picker and can build the surrounding input, popover, swatches, and form behavior yourself
- You need HEX, RGB, HSL, or HSV values with optional alpha in typed React code
- You need touch, keyboard, assistive-technology, Shadow DOM, and old-browser support from the same low-level component
- You want onChange for live preview and onChangeEnd for database writes, history entries, or other expensive work
- You want a finished design-system field with label, text input, swatches, popover, validation, and dark-mode tokens: the README presents those as recipes or separate application work
- You need arbitrary CSS color parsing: HexColorInput handles HEX forms, and each picker has a fixed color model and value shape rather than accepting every CSS color notation as one universal control
- You cannot allow runtime style injection under your Content Security Policy: the changelog says the component adds a style tag, so strict CSP deployments must provide a nonce through setNonce
- You are using Preact with TypeScript and cannot adjust conflicting React types: the README documents an extra declaration workaround when @types/react leaks into a Preact project
- You are not using React or Preact: the README points to separate ports for other frameworks, so installing this package would add an incompatible component runtime
Setup reality
npm install react-colorful gives you declarations and no runtime dependencies, but React and react-dom 16.8 or newer are peer dependencies because the components use hooks. The picker is controlled: keep color in state and update it from onChange or the handle will appear stuck. Pick the component whose value shape matches your domain; HexColorPicker uses a string, RgbColorPicker uses an object, and alpha variants change both valid input and output. Version 5.8 also exposes onChangeEnd, which fires on mouseup, touchend, or keyup and is the right place for saves or undo checkpoints; onChange still fires throughout dragging. Base picker CSS is injected at runtime, including into the closest ShadowRoot, so no package CSS import is needed. Your overrides still target static react-colorful class names, and the separate HexColorInput intentionally has no default styles. Strict CSP sites must call setNonce with the server-provided nonce before the style tag is created. All pickers accept normal div attributes, but you still own the field label, error text, popover focus management, close behavior, and how a submitted form serializes the color. HexColorInput needs alpha for four- or eight-digit HEX and prefixed to display the #. Preact usually works through React aliases, but the README documents a TypeScript declaration patch when @types/react enters the graph. IE11 needs Object.assign, according to the browser section. For server rendering, avoid deriving initial color from browser-only state and verify that the style injection fits your framework's hydration and CSP order.
Patterns
Use a controlled HEX pickerpick-hex-color
import { useState } from 'react';
import { HexColorPicker } from 'react-colorful';
export function ColorField() {
const [color, setColor] = useState('#aabbcc');
return <HexColorPicker color={color} onChange={setColor} />;
}The component is controlled; failing to update color in onChange makes the handle snap back to the old value.
Separate live preview from persistencesave-after-change
<HexColorPicker
color={color}
onChange={setColor}
onChangeEnd={(finalColor) => savePreference(finalColor)}
/>Version 5.8 onChangeEnd fires after mouse, touch, or keyboard interaction ends, avoiding a write for every drag step.
Work with typed RGB object valuespick-rgb-object
import { useState } from 'react';
import { RgbColorPicker, RgbColor } from 'react-colorful';
const [color, setColor] = useState<RgbColor>({ r: 50, g: 100, b: 150 });
return <RgbColorPicker color={color} onChange={setColor} />;Choose a string picker if your API expects CSS strings; object pickers intentionally return objects.
Use an RGBA picker with transparencypick-alpha-color
import { RgbaColorPicker, RgbaColor } from 'react-colorful';
const [color, setColor] = useState<RgbaColor>({ r: 20, g: 40, b: 60, a: 0.5 });
return <RgbaColorPicker color={color} onChange={setColor} />;Alpha is a number from 0 to 1 for RGBA objects; HEX alpha pickers instead use four- or eight-digit strings.
Pair the picker with a typed HEX inputpair-hex-input
import { HexColorInput, HexColorPicker } from 'react-colorful';
return (
<div>
<HexColorPicker color={color} onChange={setColor} />
<HexColorInput color={color} onChange={setColor} prefixed />
</div>
);HexColorInput has no default styles, so it will look like a bare browser input until your stylesheet handles it.
Allow HEX input with an alpha channelaccept-hex-alpha-input
<HexColorInput
color={color}
onChange={setColor}
alpha
prefixed
aria-label="Color including opacity"
/>Set alpha or four- and eight-digit HEX values are not accepted by the input's normal validation path.
Override the stable picker class namescustomize-picker-css
.brand-picker .react-colorful { height: 240px; }
.brand-picker .react-colorful__saturation { border-radius: 8px 8px 0 0; }
.brand-picker .react-colorful__hue { height: 32px; }
.brand-picker .react-colorful__hue-pointer { width: 14px; }Base styles are injected automatically; these selectors are overrides and should be scoped to avoid changing every picker.
Pass regular div accessibility attributesadd-accessible-label
<HexColorPicker
color={color}
onChange={setColor}
aria-label="Brand color"
className="brand-picker"
/>The picker accepts div attributes, but a complete form still needs visible label, help, validation, and focus behavior around it.
Authorize the injected stylesheet under strict CSPset-csp-nonce
import { setNonce } from 'react-colorful';
setNonce(window.__CSP_NONCE__);
// Render pickers only after the nonce is configured.The component injects a style tag; call setNonce before the first picker mounts and source the value from the server response.
Keep a serializable form value beside the pickernormalize-form-value
function ColorControl({ value, onValueChange }) {
return (
<HexColorPicker
color={value || '#000000'}
onChange={(next) => onValueChange(next.toLowerCase())}
/>
);
}react-colorful controls color interaction only; your form library still owns touched state, validation, and submission.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| react-color | npm | You want a larger collection of ready-made picker designs and accept a much heavier dependency |
| @uiw/react-color | npm | You want composable color primitives plus more packaged picker variants and utilities |
| react-color-palette | npm | You prefer a more opinionated picker with a bundled input and simpler preset UI |