JavaScript Data GridColor Picker Cell Type - Step-by-Step Guide (React)
- Overview
- What You'll Build
- Complete Example
- Prerequisites
- Step 1: Import Dependencies
- Step 2: Create the Editor Component
- Step 3: Add Styling
- Step 4: Prepare Sample Data
- Step 5: Use in Handsontable
- How It Works - Complete Flow
- Enhancements
- Accessibility
- Performance Considerations
- TypeScript Support
- Best Practices
Overview
This guide shows how to create a color picker editor cell using react-colorful's HexColorPicker with React's EditorComponent. Perfect for selecting colors in design tools, theme builders, or any scenario where users need to choose hex color values.
Difficulty: Beginner Time: ~15 minutes Libraries: react-colorful
What You'll Build
A cell that:
- Displays an input showing the hex value and a popover with a color picker when editing
- Shows the selected color as a swatch when viewing (custom renderer)
- Stores values as hex color strings (e.g.,
#FF5733) - Validates input so only valid hex values (e.g.
#RRGGBB) are accepted - Works with React's component-based architecture
- Uses
hotRendererto display color swatches in cells
Complete Example
Prerequisites
npm install @handsontable/react-wrapper react-colorful
What you need:
- React 16.8+ (hooks support)
@handsontable/react-wrapperpackagereact-colorfulpackage for the color picker UI- Basic React knowledge (hooks, JSX)
Step 1: Import Dependencies
import { HotTable, HotColumn, EditorComponent } from '@handsontable/react-wrapper';
import { registerAllModules } from 'handsontable/registry';
import { rendererFactory } from 'handsontable/renderers';
import { HexColorPicker } from 'react-colorful';
registerAllModules();
What we're importing:
EditorComponent- React component for creating custom editorsHotTableandHotColumn- React wrapper componentsrendererFactory- For the custom cell renderer (color swatch)HexColorPicker- Lightweight color picker from react-colorful
Step 2: Create the Editor Component
Create a React component that uses EditorComponent with the render prop pattern. The editor shows an input with the current hex value and a popover containing the color picker.
export const ColorPickerEditor = () => {
return (
<EditorComponent>
{({ value, setValue }) => (
<div className="color-picker-editor">
<input className="color-picker-editor-input" value={value} readOnly />
<div className="color-picker-editor-popover">
<HexColorPicker color={value || '#000000'} onChange={(color) => setValue(color)} />
</div>
</div>
)}
</EditorComponent>
);
};
What's happening:
EditorComponentwraps your editor UI- The
childrenprop is a function that receives editor state value- Current cell value (hex color string)setValue- Function to update the value- The input displays the current hex value; the popover shows
HexColorPickerfor picking a color - When the user selects a color,
setValue(color)updates the value; the editor closes on blur (e.g. clicking outside)
Key concepts:
- Render prop pattern:
EditorComponentuses a function as children - Controlled component:
HexColorPickerreceivescolorandonChange - Input + popover: The input shows the hex code; the popover is positioned below and contains the picker
Step 3: Add Styling
Style the cell (swatch display), the editor container, the input, and the popover. The popover is positioned below the editor so the color picker appears when the cell is in edit mode.
.color-picker-cell {
display: flex;
align-items: center;
justify-content: center;
}
.color-picker-swatch {
width: 18px;
height: 18px;
border-radius: 50%;
flex-shrink: 0;
border: 1px solid rgba(0, 0, 0, 0.15);
}
.color-picker-editor {
width: 100%;
height: 100%;
box-sizing: border-box !important;
border: none;
border-radius: 0;
outline: none;
}
.color-picker-editor-popover {
position: absolute;
top: 100%;
left: 0;
padding-top: 8px;
}
.color-picker-editor:focus {
outline: none;
}
.color-picker-editor-input {
width: 100%;
height: 100%;
box-sizing: border-box !important;
border: none;
border-radius: 0;
outline: none;
}
What's happening:
.color-picker-celland.color-picker-swatchdisplay a circular color swatch in the cell.color-picker-editoris the editor wrapper;.color-picker-editor-inputstyles the hex value input.color-picker-editor-popoverpositions the color picker below the editor (e.g.top: 100%,left: 0)HexColorPickerhas built-in styling from react-colorful
Step 4: Prepare Sample Data
Use an array of row objects and add a color property with random hex values. The example uses an inventory-style dataset (with columns like id, itemName, itemNo, cost, valueStock, and optionally more); you can use any structure as long as each row has a color field.
const inputData = [
{ id: 640329, itemName: 'Lunar Core', itemNo: 'XJ-12', cost: 350000, valueStock: 700000 },
{ id: 863104, itemName: 'Zero Thrusters', itemNo: 'QL-54', cost: 450000, valueStock: 0 },
// ... more rows
];
export const data = inputData.map((el) => ({
...el,
color: `#${
Math.round(0x1000000 + 0xffffff * Math.random())
.toString(16)
.slice(1)
.toUpperCase()
}`,
}));
What's happening:
- Each row is an object with columns such as
id,itemName,itemNo,cost,valueStock - A
colorproperty is added with a random hex value in#RRGGBBformat
Step 5: Use in Handsontable
Use the editor, custom renderer, and validator on the color column. The example table has multiple columns; the color column uses hotRenderer and validator.
const colorCellRenderer = rendererFactory(({ td, value }) => {
td.innerHTML = `<span class="color-picker-cell"><span class="color-picker-swatch" style="background:${value}"></span></span>`;
});
const colorValidator = (value, callback) => {
callback(value.length === 7 && value[0] === '#'); // validate hex format
};
const ExampleComponent = () => {
return (
<HotTable
data={data}
colHeaders={['ID', 'Item Name', 'Item Color', 'Item No.', 'Cost', 'Value in Stock']}
autoRowSize={true}
rowHeaders={true}
height="auto"
width="100%"
licenseKey="non-commercial-and-evaluation"
>
<HotColumn data="id" type="numeric" width={80} className="htLeft" />
<HotColumn data="itemName" type="text" width={200} className="htLeft" />
<HotColumn
data="color"
width={120}
editor={ColorPickerEditor}
hotRenderer={colorCellRenderer}
validator={colorValidator}
className="htLeft"
/>
<HotColumn data="itemNo" type="text" width={100} className="htLeft" />
<HotColumn data="cost" type="numeric" width={70} className="htLeft" />
<HotColumn data="valueStock" type="numeric" width={130} className="htRight" />
</HotTable>
);
};
What's happening:
editor={ColorPickerEditor}- Assigns the color picker editor to the columnhotRenderer={colorCellRenderer}- Renders a color swatch in the cell instead of the raw hex stringvalidator={colorValidator}- Ensures only valid hex values (e.g.#RRGGBB) are accepteddata="color"- Binds to thecolorproperty in each row; double-click opens the picker
Key features:
- Swatch display via custom renderer, validation, and type-safe editor with TypeScript
How It Works - Complete Flow
- Initial Render: Cell shows a color swatch (custom renderer); value is stored as hex (e.g.
#FF5733) - User Double-Clicks or Enter: Editor opens
- Editor Opens:
EditorComponentpositions container over cell; input shows current hex value; popover withHexColorPickerappears below - User Interaction: Drag sliders or click palette →
setValue(color)updates the value; input and picker stay in sync - Close: User blurs the editor (e.g. clicks outside) → value is saved and editor closes
- Validation:
colorValidatorensures value is valid hex before saving - Save: Hex value saved to cell; cell renderer shows the new swatch
Enhancements
1. Custom Renderer with Color Swatch (and Optional Hex Label)
The example uses hotRenderer to show only a circular swatch. You can extend it to show the hex code next to the swatch:
import { rendererFactory } from 'handsontable/renderers';
// Swatch only (as in the example)
const colorCellRenderer = rendererFactory(({ td, value }) => {
td.innerHTML = `<span class="color-picker-cell"><span class="color-picker-swatch" style="background:${value}"></span></span>`;
});
// Or swatch + hex label
const colorRendererWithHex = rendererFactory(({ td, value }) => {
const hexColor = value || '#cccccc';
td.innerHTML = `
<div style="display: flex; align-items: center; gap: 8px; padding: 4px;">
<div style="width: 24px; height: 24px; background: ${hexColor}; border: 1px solid #ddd; border-radius: 4px;"></div>
<span style="font-family: monospace; font-size: 12px;">${hexColor}</span>
</div>
`;
});
// Use hotRenderer in HotColumn
<HotColumn
data="color"
editor={ColorPickerEditor}
hotRenderer={colorCellRenderer}
validator={colorValidator}
/>
What's happening:
hotRendereris used in the React wrapper for custom cell rendering- Swatch-only keeps the cell compact; adding the hex label improves readability when needed
2. Explicit "Apply" Button (Optional)
The example closes the editor on blur. If you prefer explicit confirmation, add a button and use finishEditing from the render props:
<EditorComponent>
{({ value, setValue, finishEditing }) => (
<div className="color-picker-editor">
<input className="color-picker-editor-input" value={value} readOnly />
<div className="color-picker-editor-popover">
<HexColorPicker color={value || '#000000'} onChange={(color) => setValue(color)} />
</div>
<button className="button" type="button" onClick={() => finishEditing()}>
Apply Colour
</button>
</div>
)}
</EditorComponent>
3. Using External CSS File
The example uses a separate CSS file for cell and editor styles (e.g. example1.css). Import it in your component:
import './example1.css'; // or your color-picker-editor.css
const ColorPickerEditor = () => {
// ... component code
};
Keep the .color-picker-cell, .color-picker-swatch, .color-picker-editor, .color-picker-editor-input, and .color-picker-editor-popover rules so the swatch and the editor look correct.
4. RGBA or HSL Variants
react-colorful also provides RgbaColorPicker and HslColorPicker. For RGBA:
import { RgbaColorPicker } from 'react-colorful';
// Note: value would need to be stored as rgba string or object
// and converted appropriately
5. Default Color
Handle empty cells with a sensible default:
<HexColorPicker
color={value || '#000000'}
onChange={(color) => setValue(color)}
/>
The || '#000000' ensures the picker always has a valid color.
Accessibility
The HexColorPicker from react-colorful provides keyboard support. For the editor input, you can add an aria-label so screen readers describe the field:
<input
className="color-picker-editor-input"
value={value}
aria-label="Hex color value"
/>
Keyboard navigation:
- Tab: Navigate to editor
- Escape: Cancel editing
- Click: Direct selection in color picker
Performance Considerations
Why This Is Fast
- react-colorful: Lightweight (~2KB gzipped), no heavy dependencies
- React Virtual DOM: Efficient updates only when value changes
- Controlled updates:
onChangeonly fires when user interacts - No unnecessary re-renders: Editor unmounts when closed
Bundle Size
react-colorful is tree-shakeable. If you only need hex:
import { HexColorPicker } from 'react-colorful';
TypeScript Support
EditorComponent is fully typed. For the color editor, the value is a string (hex). You can type the validator as well:
const colorValidator = (value: string, callback: (valid: boolean) => void) => {
callback(value.length === 7 && value[0] === '#'); // validate color format
};
export const ColorPickerEditor = () => {
return (
<EditorComponent>
{({ value, setValue }) => (
<div className="color-picker-editor">
<input className="color-picker-editor-input" value={value} readOnly />
<div className="color-picker-editor-popover">
<HexColorPicker color={value || '#000000'} onChange={(color) => setValue(color)} />
</div>
</div>
)}
</EditorComponent>
);
};
Best Practices
- Provide fallback for empty values - Use
value || '#000000'for HexColorPicker - Use hotRenderer - Display color swatches in cells for better UX
- Store as hex - Hex strings are portable and easy to validate
- Input + popover - Showing the hex in an input with the picker in a popover keeps the cell compact and clear
- Optional "Apply" button - For explicit confirmation, add a button that calls
finishEditing()from the render props
Congratulations! You've created a color picker editor using React's EditorComponent and react-colorful, perfect for color selection in your data grid!