Customizing React Color’s Sketch Picker to display recently used colors
Whenever I gather materials to start a new painting, I always reach for a palette to hold the paints I’ll be using. Most often it’s a well-used piece of palette paper covered with the last painting’s color scheme. The palette makes it easy to switch between core colors without having to remix a frequently used color for each new brush stroke.
For a recent art-themed React project, I wanted to emulate the benefits of a palette and allow users to easily access their recently used colors as they ‘painted’ a digital canvas. In this post, we’ll build out this functionality by customizing React Color’s SketchPicker
component. We’ll also explore other customizations available through the SketchPicker
API that make the component a flexible and helpful tool.
You can check out the frontend repo for the project this post is based on here if you’d like more context. Code samples in this post have been simplified so we can focus on our color picker customization.
Setting up SketchPicker with Core Props
React Color is a package you can install through npm that gives you access to 13 different color picker components for use in React, ranging from sliders and swatches to input fields. You can also use helper components to create your own picker if desired.
For this demo, we’ll work with the pre-built SketchPicker
component, so let’s install the package in our app’s directory with the command npm install react-color — save.
Next we’ll import the SketchPicker
into a parent component in our app called StudioPage
, which will also render the Canvas
component our users will be painting. We’ll also set up local state in the parent component to manage the active color on the color picker.
You’ll notice that SketchPicker
is receiving two props from the parent component. Each React Color picker is prepared to receive at least two props, color
and a choice of either onChange
or onChangeComplete
.
As the React Color docs explain, color
controls the color picker’s active color. In the code snippet above, we’ve set an activeColor
value in local state that will display as the selected color when the SketchPicker
loads. For your color
prop, you can pass a hex code as a string or an object containing either RGB or HSL values. In this demo, we’ll work with hex colors.
Since the color picker’s selected/active color is controlled by the value of activeColor
in our parent component’s state, we need a way to update activeColor
each time a user selects a new color on the SketchPicker
.
To achieve this, React Color lets you pass the color picker a function to execute when a color change occurs. If you want the function to fire on every change (including drag events), pass your callback function via a prop called onChange
. If you want it to execute only once per core change, then pass your callback to onChangeComplete
.
Note that if you use onChangeComplete
, you can drag your color selector (via the hue slider or saturation block) to a new position, but the selector will not move with your cursor as you drag it. It remains stationary until you release the drag motion. Then the selector will jump to the new position. The selector does follow your pointer in a visual dragging motion if you use onChange
.
We’ll name our callback function handleChangeComplete
. Whatever callback you pass to onChange
or onChange
complete can receive both the selected color and the event as arguments. For this demo, we only need color details, so we’ll just pass in color to our callback.
Inside this callback, we’ll update the value of activeColor
in our local state and set it equal to color’s hex value by calling color.hex
. You can also access the RGB or HSL values of the selected color via color.rgb
or color.hsl
. Hex values can come through with lower or uppercase letters, so for consistency, we’ll save the values in uppercase format. This becomes important later when we build out our recent colors tracking feature.
Customizing the Color Picker
Now that we have the base functionality setup, let’s explore ways to customize the SketchPicker
.
Some of the color picker options come with their own APIs, which are outlined in the React Color docs. SketchPicker lets you pass additional props if desired, including:
disableAlpha
Alpha describes the opacity of a color. If you don’t want to display alpha values on the color picker, pass disableAlpha the boolean value true
(set to false by default). Make sure to pass true
as a boolean value, not a string. Since opacity did not factor into the app I was working on, I chose to disable this feature.
width
The SketchPicker
’s width is set to 200px by default, but you can pass in a new value to change the width. I chose to use a percentage so the picker would scale with its container.
className
If you want to further adjust the component’s style, use the className
prop to pass in your own styles. Since we don’t have access to the picker’s styles, you might need to override them in your CSS if you want to change already set values.
onSwatchHover
You can customize the hover behavior of the SketchPicker
’s preset color swatches. Add an onSwatchHover
prop to your picker and pass it a callback function that executes your desired hover action. The callback function will be able to receive both color
(i.e. the selected color) and event
as arguments.
presetColors
The SketchPicker
displays 15 color swatches by default, but you can pass your own set of colors as either hex codes or RGB/HSL objects. You can also pass in more or less than 15 options. We’ll use this prop to transform the color swatches section into our own paint palette that tracks recently used colors.
Tracking Recently Used Colors in our Picker
Returning to our original goal, if a user works with a custom color pulled from the slider or saturation block, we want to keep track of that color so they can easily return to it later and not have to place their slider/selector in the exact same location. It’s hard, I’ve tried it.
In the code sample above, you may have noticed we’re passing this.state.presetColors
as the presetColors
prop to our color picker.
In our parent component’s local state, we’ll add presetColors
and set it equal to the default presetColor
values provided by the SketchPicker
.
These 15 default colors provide a nice starting palette, but we’ll update this slice of state with each new color used so that it becomes a rotating color palette displaying recently used colors.
In the app I worked on, a user can click on shapes within an SVG, our <Canvas />
component, to add colors. Each click triggers a callback action, handleClick
, in StudioPage
that accepts the shape’s id and the currently active color. It then dispatches an action via a prop called addColor
that updates the shape’s color. Understanding this user interaction is relevant because it helps determine when a color becomes ‘recently used’. In this case, we can say a color becomes ‘recently used’ when a user adds it to a canvas shape, or in other words, when a click event happens on the canvas.
Now let’s take a look at the handleClick
function we’re passing to our Canvas
component.
As mentioned above, this function accepts a shape/polygon id and the active color from our color picker. The first line handles updating our canvas and isn’t our focus here. Instead, let’s walk through the logic in the rest of the function.
Each time a user fills a shape with a color and triggers this function, we only want to add the color added to our swatch collection if it isn’t already present. To achieve this, we’ll use a conditional:
if(!this.state.presetColors.includes(activeColor))
Remember when we made sure our active color was stored as a hex value in uppercase format? Since we know all our colors in our presetColors array are stored in the same format, we can check to see if the array contains the color that was just used on our canvas. If it doesn’t, then we move into the block to update state.
setState
is a built-in React function that lets us update our state. Because we’ll need to build on the current values in our presetColors array, we’ll pass in a callback function to setState
. (If you’re updating state based on previous state, it’s best practice to use this format because of setState
’s asynchronous nature). When we pass a function to setState
, this function can access our component’s state (often called previous state) as an argument.
We’ll pass in an argument named state
to represent this previous state. Keeping with best practices, we’ll avoid mutating state directly and create a copy of our presetColors array for editing.
const colors = state.presetColors.slice(0)
Next we’ll add the used color to the beginning of our array and remove the last color so our array stays at a length of 15 colors.
colors.unshift(activeColor)
colors.pop()
Finally, we’ll return the updated value of presetColors, updating our local state. Because our SketchPicker relies on the value of presetColors, it will be re-rendered and the row of 15 swatches will now include the just-used color. Just what we want!
Wrapping Up
We now know how to customize the SketchPicker
component available through React Color. By providing ways to adjust preset colors, width, hover effects, and alpha features, the component becomes a flexible and easy-to-adapt interface for color selection. Other color pickers come with their own customizations, so browse the React Color docs to learn more. If you want to customize even further, check out the section about creating your own color picker using their helper components.