DEV Community

Cover image for Building a tints and shades colour generator with React and Values.js
David Asaolu
David Asaolu

Posted on

Building a tints and shades colour generator with React and Values.js

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

Adding Chakra UI to a React app

Chakra UI 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.

npx create-react-app colour-generator
Enter fullscreen mode Exit fullscreen mode

Install Chakra UI and React Router - a JavaScript library that enables us to navigate between the pages of a React app.

npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion react-router-dom
Enter fullscreen mode Exit fullscreen mode

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.

function App() {
    return (
        <div>
            <p>Hello World!</p>
        </div>
    );
}
export default App;
Enter fullscreen mode Exit fullscreen mode

Update the index.css file to contain the code snippet below. It enables us to use the custom Google font.

@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;
}
Enter fullscreen mode Exit fullscreen mode

Configure React Router and Chakra UI by copying the code below into the index.js file.

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>
);
Enter fullscreen mode Exit fullscreen mode

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.

mkdir components
cd components
touch Home.js Colours.js
Enter fullscreen mode Exit fullscreen mode

Before we start designing each component, update the App.js file to render each component on its specific route as done below:

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;
Enter fullscreen mode Exit fullscreen mode

The Home component

Copy the code below into the Home.js file.

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;
Enter fullscreen mode Exit fullscreen mode

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

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 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.

npm install values.js
Enter fullscreen mode Exit fullscreen mode

Recall that the Colours.js component is a dynamic route that accepts the colour code provided by the user as a parameter (id).

<Route path='/colour/:id' element={<Colours />} />
Enter fullscreen mode Exit fullscreen mode

Next, pass the colour code into the Values.js package and request its tints and shades.

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;
Enter fullscreen mode Exit fullscreen mode
  • 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.

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;
Enter fullscreen mode Exit fullscreen mode

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.

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;
Enter fullscreen mode Exit fullscreen mode

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

The 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.

npm install --save react-copy-to-clipboard
Enter fullscreen mode Exit fullscreen mode

Import the CopyToClipboard component from its library.

import CopyToClipboard from "react-copy-to-clipboard";
Enter fullscreen mode Exit fullscreen mode

Wrap the entire ShadesComponent with the CopyToClipboard component.

return (
    <CopyToClipboard onCopy={onCopy} text={`#${shade.hex}`}>
        {/*-- other UI elements--*/}
    </CopyToClipboard>
);
Enter fullscreen mode Exit fullscreen mode

Create the onCopy function. It changes the colour's name to "copied" to notify the user and sets it back.

const onCopy = () => {
    let value = shade.hex;
    setValue("Copied");
    setTimeout(() => {
        setValue(`#${value}`);
    }, 1000);
};
Enter fullscreen mode Exit fullscreen mode

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

The source code for this tutorial is available here. 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 || LinkedIn || Twitter

Buy David a coffee
Thank You

Top comments (4)

Collapse
 
efpage profile image
Eckehard

This is a nice app to make colour numbers more accessible. Just: why did you not use a color selector to choose the initial color? If you do not hit the right color initially, there is no way to do an interactive selection. There are plenty of nice webcomponents out there like

Shoelace provides a nice tool that even letยดs you select colors from the window screen. Even Cahkra provides a color picker, which - a least in the sandbox - seems tio be a bit limited.

Anyway, thank you for mentioning Chakra UI!

Collapse
 
arshadayvid profile image
David Asaolu

Noted, thank you @efpage for the recommendation.

Collapse
 
sm0ke profile image
Sm0ke

Great post.

Collapse
 
arshadayvid profile image
David Asaolu

Thank you! @sm0ke