Thieving Your Way to a Dynamic Colour Theme in React
Dynamically set the colour palette of your React components with color-thief-react.
Time to read: ~2 minutes
Published: Sunday, November 7th 2021
Table of Contents
I always thought it was really cool how some applications were able to dynamically set the colour of components on their page based on an image that was being displayed.
I wanted to get this kind of effect myself, and luckily discovered a javascript library, Color Thief React, that provides components and hooks for Color Thief, making it super easy to use Color Thief from a React application. This article will cover how to use the library as well as demonstrate a little demo of what you can get out of it.
There are two main components included in this package: Color and Palette. Color will get you a single dominant colour from a source image while Palette will return a number of colours. Both of these components are also available as hooks. If you want to take a deeper dive into the details about this package, you should check out the README in the github repo.
Getting Started
I'm starting off with a bare bones create-react-app with all the extra fluff removed.
Next we want to install the package.
npm i -S color-thief-react
Matching the Colour of a Source Image
I'm a big fan of react hooks and it makes things super simple. Inside a functional component, it's as easy as adding the following snippet.
import imgSrc from './images/{whateverImage.ext}';
import { useColor } from 'color-thief-react';
function ColourMatcher() {
const { data } = useColor(imgSrc, 'hex');
return (
<div>
<img src={imgSrc} />
<p style={{ color: data }}>My colour matches!</p>
</div>
);
}
Here we grab an image from our local directory (alternatively you can pull an image from an online source), and use it inside the useColor
react hook along with our desired colour format. We can access this colour data using data
. Now we can use the data to specify the colour for our elements!
And here is what things should look like if you did things correctly:
The useColor hook also provides access to two additional properties: loading
and error
. Pull in react's useEffect
for monitoring the status of the loading
property and you can add some neat reactiveness to your application!
const { data, loading, error } = useColor(imgSrc, 'hex');
useEffect(() => {
if (loading)
console.log('still loading...');
else if (error)
console.error(error);
else
console.log('got a color!', data);
}, [loading]);
Matching the Palette of a Source Image
Now if you need more than a single colour, you might want to extract a palette from the image instead. Check out the example below!
import { usePalette } from 'color-thief-react';
function PaletteMatcher() {
const numColours = 3;
const colourFormat = 'hex';
const { data, loading, error } = usePalette(imgSrc, numColours, colourFormat);
return (
<div>
<img src={imgSrc} />
{
loading
? <p>Loading...</p>
: (data.map(colorData => {
return (<p style={{ color: colorData }}>My palette matches!</p>);
}))
}
</div>
);
}
And voila! Color thief was able to extract the top 3 colours from the image so that I could use it to colour the text elements (one of the colours was super bright so you may not be able to see it).
Demo
With this, you can achieve some pretty cool dynamic theming with colours that match your media. Check out this demo which selects colours from the palettes of the album covers of some of my favourite music artists.
Wrapping Up
So now you see how easy it is to get this working and how it can help to add some cohesivness to the elements accompanying your media in your application. To build on this, I'll be looking for a solution that ensures that text has appropriate contrast with its background. I'll be discussing this in one of my posts in the future so stay tuned for that!
Thanks for reading, now go build some stuff!