Building a tints and shades colour generator with React and Values.js
Tags: react, javascript, tutorial, programming
Published: 2023-05-01 11:00:00

Hey there👋🏻,
In this article, you'll learn how to create a web application that generates various tints and shades of colours using React, ChakraUI, and Values.js.
Users will provide the hex code of any colour then the app generates various tints and shades of the colour. 


![Building a tints and shade generator with React and Chakra UI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/at6ljrbl0tzfvwt8xe2l.gif)

## Adding Chakra UI to a React app
[Chakra UI](https://chakra-ui.com) is a library that allows you to build stunning and modern web applications using various UI components. It differs from other UI frameworks because it offers accessibility and dark mode support by default. Follow the steps below to Chakra UI to a React app.

Create a new React.js project by running the code below.

```bash
npx create-react-app colour-generator
```
Install Chakra UI and [React Router](https://reactrouter.com/en/main) - a JavaScript library that enables us to navigate between the pages of a React app.

```bash
npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion react-router-dom
```
The other packages are Chakra UI dependencies.

Delete the redundant files, such as the logo and the test files from the React app, and update the `App.js` file to display “Hello World” as done below.

```jsx
function App() {
	return (
		<div>
			<p>Hello World!</p>
		</div>
	);
}
export default App;
```
Update the `index.css` file to contain the code snippet below. It enables us to use the custom [Google font](https://fonts.google.com).
```css
@import url("https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap");
* {
	margin: 0;
	box-sizing: border-box;
	padding: 0;
	font-family: "Space Grotesk", sans-serif;
}
```
Configure React Router and Chakra UI by copying the code below into the `index.js` file.
```js
import React from "react";
import ReactDOM from "react-dom/client";
import { ChakraProvider, extendTheme } from "@chakra-ui/react";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
import "./index.css";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
	<React.StrictMode>
		<ChakraProvider
			theme={extendTheme({
				fonts: {
					body: "Space Grotesk",
					heading: "Space Grotesk",
				},
			})}
		>
			<BrowserRouter>
				<App />
			</BrowserRouter>
		</ChakraProvider>
	</React.StrictMode>
);
```
The code snippet above wraps the entire application with the `ChakraProvider` component, which provides access to all the UI components Chakra UI provides. The `ChakraProvider` also enables us to change the font type of its component via the `extendTheme` function.

Congratulations!🎉 You have successfully configured Chakra UI and now have access to all its components.

## Building the application user interface
Here, I'll walk you through building the entire user interface for the application with Chakra UI.

The application is divided into two pages - the `Home.js` component and the `Colours.js` component. Create a components folder containing both files.
```bash
mkdir components
cd components
touch Home.js Colours.js
```
Before we start designing each component, update the `App.js` file to render each component on its specific route as done below:
```js
import React from "react";
import { Route, Routes } from "react-router-dom";
import Home from "./components/Home";
import Colours from "./components/Colours";

const App = () => {
	return (
		<div style={{ backgroundColor: "#F1F6F9" }}>
			<Routes>
				<Route path='/' element={<Home />} />
				<Route path='/colour/:id' element={<Colours />} />
			</Routes>
		</div>
	);
};

export default App;
```
### The Home component
Copy the code below into the `Home.js` file.
```js
import {
	Box,
	Button,
	Flex,
	FormControl,
	Heading,
	Icon,
	Input,
	Text,
	Alert,
	AlertTitle,
	AlertIcon,
} from "@chakra-ui/react";
import React, { useState } from "react";
import { FaGithub, FaTwitter } from "react-icons/fa";
import { useNavigate } from "react-router-dom";

const Home = () => {
	let [colour, setColour] = useState("");
	const [alert, setAlert] = useState(false);
	const navigate = useNavigate();

	const redirectPage = (e) => {
		e.preventDefault();
		if (colour.startsWith("#") && colour.length >= 4) {
			//👇🏻 removes the # sign before redirecting the user
			colour = colour.substring(1);
			return navigate(`/colour/${colour}`);
		} else {
			setAlert(true);
		}
	};
	return (
		<Box>
			<Flex
				w='full'
				h='10vh'
				p={{ base: "10px 30px", md: "10px 40px" }}
				alignItems='center'
				justifyContent='space-between'
				borderBottom='1px'
				borderBottomColor='gray.200'
			>
				<Text fontSize='26px' color='gray.600' fontWeight='bold'>
					TintTastic
				</Text>
				<Flex alignItems='center'>
					<a
						href='https://github.com/dha-stix/tints-shade-generator'
						target='_blank'
						rel='noreferrer'
					>
						<Icon
							as={FaGithub}
							boxSize={6}
							color='#9BA4B5'
							cursor='pointer'
							_hover={{ color: "#212A3E" }}
							mr='50px'
						/>
					</a>
					<a
						href='https://twitter.com/dayvid_JS'
						target='_blank'
						rel='noreferrer'
					>
						<Icon
							as={FaTwitter}
							boxSize={6}
							color='#9BA4B5'
							cursor='pointer'
							_hover={{ color: "#212A3E" }}
						/>
					</a>
				</Flex>
			</Flex>
			<Flex
				alignItems='center'
				justifyContent='center'
				minH='90vh'
				p={{ base: "30px", md: "30px 80px" }}
				flexDirection='column'
			>
				<Heading
					as='h1'
					size='3xl'
					textAlign={{ base: "left", md: "center" }}
					fontWeight='900'
					mb='30px'
				>
					<span
						style={{
							color: "#F97B22",
						}}
					>
						Effortlessly
					</span>{" "}
					create beautiful color palettes for your projects
				</Heading>
				<Heading
					as='h4'
					size='md'
					fontWeight='normal'
					textAlign={{ base: "left", md: "center" }}
					mb='30px'
				>
					TintTastic is a user-friendly tint and shade generator that will
					elevate your color game in no time.
				</Heading>

				<FormControl
					as='form'
					display='flex'
					alignItems={{ base: "left", md: "center" }}
					justifyContent='center'
					flexDirection={{ base: "column", md: "row" }}
					onSubmit={redirectPage}
				>
					<Input
						placeholder='#ffffff'
						type='text'
						name='color'
						id='color'
						w={{ base: "full", md: "50%" }}
						mr='30px'
						required
						mb={{ base: "15px", md: "0px" }}
						value={colour}
						onChange={(e) => setColour(e.target.value)}
					/>
					<Button
						w={{ lg: "25%" }}
						colorScheme='orange'
						size='lg'
						type='submit'
					>
						Generate Shades
					</Button>
				</FormControl>
				{alert && (
					<Alert
						status='error'
						w={{ base: "full", lg: "50%" }}
						mt='30px'
						borderRadius='5px'
					>
						<AlertIcon />
						<AlertTitle>Only accepts hex code values!</AlertTitle>
					</Alert>
				)}
			</Flex>
		</Box>
	);
};

export default Home;
```
The code snippet above displays a fully responsive home page using various Chakra UI components and allows us to enter the hex code of the colour we need to generate its tints and shades.

The `redirectPage` function validates the user's input and redirects the user to the Colour page. If the user's input is invalid, it sets the `alert` state to true. The `alert` state displays an error alert when its value is "true".

![Tints and Shades Generator](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xxbx5wck5m48u0ot4ooi.png)

## Generating tints and shades of a colour with Values.js
Here, you'll learn how to generate the tints and shades of various colours using the `Values.js` package.

> [Values.js](https://noeldelgado.github.io/values.js) is an open-source package that enables us to generate the tints and shades of any colour.

Install the Values.js package by running the code below.

```bash
npm install values.js
```
Recall that the `Colours.js` component is a dynamic route that accepts the colour code provided by the user as a parameter (id).
```jsx
<Route path='/colour/:id' element={<Colours />} />
```
Next, pass the colour code into the `Values.js` package and request its tints and shades.
```jsx
import React, { useEffect, useState } from "react";
import { Box, Flex, Heading } from "@chakra-ui/react";
import ColourShades from "./ColourShades";
import { Link, useParams } from "react-router-dom";
import Values from "values.js";

const Colours = () => {
	const { id } = useParams();
	const [shades, setShades] = useState([]);
	const [error, setError] = useState(false);

	useEffect(() => {
		function fetchShades() {
			try {
				let shades = new Values(`#${id}`).all(10);
				setShades(shades);
			} catch (err) {
				setError(true);
			}
		}
		fetchShades();
	}, [id]);

	return (
		<Box w='full' minH='100vh'>
			<Flex
				h='10vh'
				w='full'
				position='sticky'
				top='0'
				alignItems='center'
				justifyContent='center'
				bg={!error && shades.length > 0 ? `#${shades[10].hex}` : "#ffffff"}
				borderBottom='1px'
				borderBottomColor='gray.200'
			>
				<Link to='/'>
					<Heading as='h3' size='md' color='gray.600'>
						#{id}
					</Heading>
				</Link>
			</Flex>
			<ColourShades shades={shades} error={error} />
		</Box>
	);
};

export default Colours;
```
- From the code snippet above,
  - The `useEffect` hook passes the colour code into the `Values.js` package to generate ten tints and shades of the colour. 
  - The `shades` array saves the colour tints and shades, and the `error` state is set to "true" when there is an error.
  - The `ColourShades` component accepts the shades and error states as props.

Create the `ColourShades` component and copy the code below into the component.
```jsx
import { Flex, Heading } from "@chakra-ui/react";
import React from "react";
import ShadesComponent from "./ShadesComponent";

const ColourShades = ({ shades, error }) => {
	return (
		<Flex
			p='30px'
			alignItems='center'
			flexWrap='wrap'
			justifyContent='center'
			minH='90vh'
		>
			{error ? (
				<Heading as='h3' color='red.500'>
					Incorrect hex code value
				</Heading>
			) : (
				shades.map((shade, index) => (
					<ShadesComponent key={index} shade={shade} />
				))
			)}
		</Flex>
	);
};

export default ColourShades;
```
From the code snippet above, the `ColourShades` component accepts both the shades and the error state. Then, render an error message if there is an error; otherwise, it maps all the colours generated into another component called `ShadesComponent`.

The `ShadesComponent` represents each colour box. Copy the code below into the `ShadesComponent` component.
```jsx
import React, { useState } from "react";
import { Flex, Text } from "@chakra-ui/react";

const ShadesComponent = ({ shade }) => {
	const [value, setValue] = useState(`#${shade.hex}`);

	return (
		<Flex
			bg={`#${shade.hex}`}
			w='200px'
			h='200px'
			p='10px'
			m='10px'
			cursor='pointer'
			alignItems='flex-end'
			justifyContent='right'
			_hover={{ boxShadow: "md" }}
			borderRadius='md'
		>
			<Text bg='#F1F6F9' p='5px' borderRadius='5px' fontSize='xs'>
				{value}
			</Text>
		</Flex>
	);
};

export default ShadesComponent;
```

## How to copy the colour codes on button click
To complete this application, we need to add a final feature that allows us to copy the colour code on button click.

![TintTastic Tints and Shade Generator](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oamre348xishbwiso6lm.gif)

> The [React Copy-to-clipboard](https://github.com/nkbt/react-copy-to-clipboard) is a simple JavaScript package that allows us to copy and paste contents via a button click.

Install the React Copy-to-clipboard library by running the code below.
```bash
npm install --save react-copy-to-clipboard
```
Import the `CopyToClipboard` component from its library.

```js
import CopyToClipboard from "react-copy-to-clipboard";
```
Wrap the entire `ShadesComponent` with the `CopyToClipboard` component.

```jsx
return (
	<CopyToClipboard onCopy={onCopy} text={`#${shade.hex}`}>
		{/*-- other UI elements--*/}
	</CopyToClipboard>
);
```
Create the `onCopy` function. It changes the colour's name to "copied" to notify the user and sets it back.
```js
const onCopy = () => {
	let value = shade.hex;
	setValue("Copied");
	setTimeout(() => {
		setValue(`#${value}`);
	}, 1000);
};
```
Congratulations!🎉 You've completed the project for this tutorial.

## Wrap-up
So far, you've learnt,

- what Chakra UI is and how to add Chakra UI to a React project,
- how to generate tints and shades of colours using Values.js, and
- how to copy contents on button click in React.

Here is a live demo of the application: [https://tints-shade-generator.vercel.app](https://tints-shade-generator.vercel.app/)

The source code for this tutorial is available [here](https://github.com/dha-stix/tints-shade-generator). Feel free to star, fork, and contribute to the project.

### Open to work🙂
Did you enjoy this article or need an experienced Technical Writer for a remote, full-time, or contract-based role? Feel free to contact me.
[GitHub](https://github.com/dha-stix) ||  [LinkedIn](https://www.linkedin.com/in/david-asaolu234/) ||  [Twitter](https://twitter.com/dayvid_JS)

[![Buy David a coffee](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cinwy8wfhl6ra51t6ml5.png)](https://www.buymeacoffee.com/asaoludavid)
<img src="https://media.giphy.com/media/fVtcfEXWQJQUbsF1sH/giphy.gif" alt="Thank You" width="auto" height="auto"/>