May 20, 2020
Colors are fun. Especially when you can choose your own. You’ll need a color picker for that though. Luckily, we can easily create a custom one ourselves with react
.
While you can use the native color picker that the browser offers, we’ll be using the library react-color
. It provides us with a couple of helpful components, which speed up the progress of making a picker. So first we install react-color
.
yarn add react-color
Once installed we can immediately started coding. The library is built in such a way that it offers a higher order component
that you need to wrap around a component of your own. The higher order component provides you with functionality we’ll go through later. First let’s import the HoC and make a component to wrap around.
import {CustomPicker} from "react-color"
class ColorPicker extends React.Component {
render() {
return (
<div>
our amazing picker
</div>
)
}
}
and then let’s wrap the CustomPicker higher order component around it.
const ColorPickerWrapped = CustomPicker(ColorPicker);
If at this point you console.log
the this.props
of the ColorPicker component, you see that we’ve just got a bunch of props.
color: Object
hsl: Object
hex: "#22194d"
rgb: Object
hsv: Object
oldHue: 250
source: undefined
onChange: function () {}
There is a color
prop we’ll discuss in a minute, but there are also an hsl
prop, a hex
prop, a rgb
prop and an hsv
prop. These are all color formats that may or may not be useful too you. The great thing about the library is that it provides you with all of them, and is fine with you providing only one.
Let’s get to that color
prop. We need a piece of state to keep track of the color we’re selecting in our yet to make picker. We’re going to keep that state not in the ColorPicker component itself, but we’re going to lift it a component higher.
export default function App() {
const [color, setColor] = useState("#FFF000");
return (
<div
style={{
position: "fixed",
width: "100%",
height: "100%",
margin: 0,
padding: 0,
background: backgroundColor
}}
>
<h1>A Custom Color Picker with react-color</h1>
<ColorPickerWrapped
color={color}
setColor={setColor}
/>
</div>
);
}
As you can see we created a new component that keeps the color in a piece of state. We pass that state as a prop to our earlier wrapped ColorPicker. The reason that we keep this state in a parent component, is that the prop needs to passed to the wrapping component to do its converting magic. If you check the props again of the ColorPicker you can now see that the default hex color we provided in the state has now been converted to rgba, hsl and hsv for us. We still can’t change the color though. Let’s include one of the helper components from react-color. We can start with a simple one: a simple input to change the hex code of the color.
var { EditableInput } = require("react-color/lib/components/common");
<EditableInput
value={this.props.hex}
onChange={data => this.handleChange(data.Hex)}
/>
The EditableInput component needs at the minimum these two props: a value
prop to display what the value of the input field is, and an onChange
handler to handle the new values that are typed into the field. We can use the hex
prop from the higher order component for the value
. For the onChange
handler we need to create a little function.
handleChange = data => {
this.props.setColor(data);
};
It just takes the Hex
property of the data
object and then calls the setColor
function we passed down from the parent component. That will change the color in the state, which is then passed down again and correctly displayed in the input field. We now have a very barebones custom color picker!
Still, this is no fun. We need a saturation picker. Let’s import it and set it up.
<div
style={{
float: "left",
width: "200px",
height: "200px",
position: "relative"
}}
>
<Saturation
{...this.props}
onChange={this.handleChange}
pointer={Picker}
/>
</div>
Okay, this one has some more meat on the bones. First off, you need to wrap this component in a div
with position: relative
. This is because the Saturation component is positioned absolute
. Next the component needs the props the wrapper provides. So might as well pass ‘em all down by destructuring this.props
.
The onChange
should seem familiar. You can use the same helper function, but no need to specifically pass a property of an object. Just pass it all! Then there is the pointer
prop. It is optional and you can leave it empty. However, you may also pass a custom component to configure your own little picker. Let’s do that quickly.
function Picker() {
return (
<div
style={{
width: 20,
height: 20,
borderRadius: 20,
background: "rgba(255,255,255,0.2)",
border: "1px solid white",
boxShadow: "0px 2px 4px rgba(0, 0, 0, 0.25)",
boxSizing: "border-box"
}}
/>
);
}
Ok done. Save the file and now behold a very cool saturation picker. The fun thing is that you should see your hex
input field be updated as you drag the picker across the saturation picker. And vice-versa.
In the same vain we can now also add a hue picker.
<div
style={{
float: "left",
width: "200px",
height: "20px",
position: "relative"
}}
>
<Hue
{...this.props}
onChange={this.handleChange}
pointer={Picker}
/>
</div>
You’ll notice there isn’t much different from the saturation picker. While we’re at it let’s also include an alpha picker. This will let us select a see-through shade :)
<div
style={{
float: "left",
width: "200px",
height: "20px",
position: "relative"
}}
>
<Alpha
{...this.props}
pointer={Picker}
onChange={this.handleChange}
/>
</div>
Awesome! We’ve now created a pretty cool color picker. Let’s put it into practice. How about we use the color picker we just created to change our background color. First we’ll need to set up some state in the parent component, and some styling.
export default function App() {
const [color, setColor] = useState("#FFF000");
const [backgroundColor, setBackgroundColor] = useState("#FFFFFF");
return (
<div
style={{
position: "fixed",
width: "100%",
height: "100%",
margin: 0,
padding: 0,
background: backgroundColor
}}
>
<h1>A Custom Color Picker with react-color</h1>
<ColorPickerWrapped
color={color}
setColor={setColor}
setBackgroundColor={setBackgroundColor}
/>
</div>
);
}
So there is now some state, a function to set the background color and we’ve added styling based on the state.
Since we’ve got those fancy pickers we don’t want to suffice for just a regular ol’ hex color, we want a rgba
color with alpha. We know that react-color provides the values we need for that. So basically the only thing we need to do is create a button that confirms our color choice, and then have a helper function that takes the rgba value from the higher order component, which is then passed into the setBackgroundColor
function as valid css
.
selectColor = color => {
const rgba = `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a})`;
this.props.setBackgroundColor(rgba);
};
<button onClick={() => this.selectColor(this.props.rgb)}>
Select a color
</button>
There we go. The rgb
prop from the HoC provides us with an object that contains the seperate values for the r
, g
, b
and a
. Our styling expects an rgba
value that is formatted like: “rgba(r,g,b,a)”, so all we need to do is format it like that using a template string.
With those additions in place we have completed our custom color picker. You may now include your own styling, fantasy and use it in the wild.
Full code: https://codesandbox.io/s/just-a-custom-color-picker-uu6v3?file=/src/App.js