DEV Community

Cover image for How to code a simple linear gradient generator using ReactJS.
Anubhav Shukla
Anubhav Shukla

Posted on

How to code a simple linear gradient generator using ReactJS.

This is what we are going to code.

Linear gradient Generator
Final code link


For styling our react app I am going to use style-components. If you don't know or want a refresher refer to this awesome article.

Now let the fun begins........

import React from "react";
import styled from "styled-components";

const GradientContainer = styled.div``;

const App = () => {
return (
// Here I will begin the code
}

export default App
Enter fullscreen mode Exit fullscreen mode

This is the basic setup for our app. I am writing my code in the App component, you can write in whatever component you want.

Also, I am going to write all my styles inside GradientContainer. You can style your react app however you want.

First, let's code the structure of our app

       <GradientContainer>
    <div className="gradient_container_header">
      <h1 className="gradient_container_header_heading">
        Gradient Generator
      </h1>
      <h3 className="gradient_container_header_subheading">
        Generate your gradient
      </h3>
    </div>
    <div className="gradient_container_main">
      <div className="gradient_container_main_color_box">

         // first ColorInput will go here
        <div className="gradient_conatiner_main_color_box_range">

        // first Range Input

        </div>
      </div>
      <div className="gradient_container_main_gradient_box">

       // Gradient Box will go here


      </div>
      <div className="gradient_container_main_color_box">

       // Second ColorInput will go here

        <div className="gradient_conatiner_main_color_box_range">

       // Second Range Input will go here


        </div>
      </div>
    </div>
    <div className="gradient_container_footer">
      <h3>In Deg</h3>

      // Third Range Input will go here


      <h3 className="gradient_container_footer_text">
        Code for the gradient that you have generated
      </h3>
      <h1 className="gradient_container_footer_code">

      // Code will go here


      </h1>
    </div>
  </GradientContainer>
Enter fullscreen mode Exit fullscreen mode

Output
Output of the above code

Now let's understand the above structure line by line.

I created a div with className "gradient_container_header" which will act as a container for our header element.

Below this, the structure is a little bit complex and hard to understand but I will try my best to tell you as simple as possible.
First, let's understand what structure we are aiming for.
Structure detail

Here, you can see the mid part contain 3 component:- Color Picker and Range part || Gradient part || Color Picker and Range part

Therefore I created a div with className "gradient_container_main" which will act as a mid-part and inside that div, I have created three more div which will contain the three components, and with the help of flex-box we will achieve what we are aiming for.

Styling our structure.

const GradientContainer = styled.div`
  .gradient_container_header {
    text-align: center;
    .gradient_container_header_heading {
      font-size: max(3vw, 20px);
    }
    .gradient_container_header_subheading {
      font-size: max(1.5vw, 10px);
      color: rgba(0, 0, 0, 0.5);
    }
  }

  /* To arrange the components side by side */
  .gradient_container_main {
    display: flex;
    justify-content: center;
    gap: 5em;

    .gradient_container_main_color_box {
      display: flex;
      flex-direction: column;
      gap: 5em;
      align-items: center;
      justify-content: center;

      /* To rotate the range input */
      .gradient_conatiner_main_color_box_range {
        height: max-content;
        transform: rotateZ(-90deg);
      }
    }
  }
  .gradient_container_footer {
    text-align: center;
  }
`;
Enter fullscreen mode Exit fullscreen mode

Output
Output of the above code

How to code color picker

Linear gradient Generator

Here we are using a two color picker so instead of coding the color picker inside the app component (or whatever component you are currently working on ) it will be more convenient to make it a separate component and use that component wherever we want the color picker.

import React from "react";
import styled from "styled-components";

const ColorInputStyle = styled.input``;
const ColorInput = (props) => (
  <ColorInputStyle
    type="color"
  />
);
export default ColorInput;
Enter fullscreen mode Exit fullscreen mode

Now let's use this component inside the App

    <GradientContainer>
    <div className="gradient_container_header">
      <h1 className="gradient_container_header_heading">
        Gradient Generator
      </h1>
      <h3 className="gradient_container_header_subheading">
        Generate your gradient
      </h3>
    </div>
    <div className="gradient_container_main">
      <div className="gradient_container_main_color_box">

         <ColorInput />
        <div className="gradient_conatiner_main_color_box_range">

        // first Range Input

        </div>
      </div>
      <div className="gradient_container_main_gradient_box">

       // Gradient Box will go here


      </div>
      <div className="gradient_container_main_color_box">

       <ColorInput />

        <div className="gradient_conatiner_main_color_box_range">

       // Second Range Input will go here


        </div>
      </div>
    </div>
    <div className="gradient_container_footer">
      <h3>In Deg</h3>

      // Third Range Input will go here


      <h3 className="gradient_container_footer_text">
        Code for the gradient that you have generated
      </h3>
      <h1 className="gradient_container_footer_code">

      // Code will go here


      </h1>
    </div>
  </GradientContainer>
Enter fullscreen mode Exit fullscreen mode

Output
Output of the code

Now let's add some styling to our colorInput

import React from "react";
import styled from "styled-components";

const ColorInputStyle = styled.input`
  border-radius: 50%;
  width: max(5vw, 50px);
  height: max(5vw, 50px);
`;
const ColorInput = (pros) => (
  <ColorInputStyle
    type="color"
  />
);
export default ColorInput;
Enter fullscreen mode Exit fullscreen mode

Output
Output of the above code

Notice how the main color area is still square. The code to make it a circle is given below

import React from "react";
import styled from "styled-components";

const ColorInputStyle = styled.input`
  border-radius: 50%;
  width: max(5vw, 50px);
  height: max(5vw, 50px);

  &::-webkit-color-swatch {
    border-radius: 50%;
  }
  &::-moz-color-swatch {
    border-radius: 50%;
  }
`;
const ColorInput = (pros) => (
  <ColorInputStyle
    type="color"
  />
);
export default ColorInput;
Enter fullscreen mode Exit fullscreen mode

Output
Output of the above code

Now it's look perfect😍.

How to code range input

import React from "react";
import styled from "styled-components";

const RangeInputStyle = styled.input``;
const RangeInput = (props) => (
  <RangeInputStyle
    type="range"
    min={0}
    max={100}
  />
);
export default RangeInput;
Enter fullscreen mode Exit fullscreen mode

Now lets use this this inside our App component

<GradientContainer>
      <div className="gradient_container_header">
        <h1 className="gradient_container_header_heading">
          Gradient Generator
        </h1>
        <h3 className="gradient_container_header_subheading">
          Generate your gradient
        </h3>
      </div>
      <div className="gradient_container_main">
        <div className="gradient_container_main_color_box">
          <ColorInput />

          <div className="gradient_conatiner_main_color_box_range">
            <RangeInput />
          </div>
        </div>
        <div className="gradient_container_main_gradient_box">
          // Gradient Box will go here
        </div>
        <div className="gradient_container_main_color_box">
          <ColorInput />

          <div className="gradient_conatiner_main_color_box_range">
            <RangeInput />
          </div>
        </div>
      </div>
      <div className="gradient_container_footer">
        <h3>In Deg</h3>

        <RangeInput />

        <h3 className="gradient_container_footer_text">
          Code for the gradient that you have generated
        </h3>
        <h1 className="gradient_container_footer_code">// Code will go here</h1>
      </div>
    </GradientContainer>
Enter fullscreen mode Exit fullscreen mode

Output
output of the above code

Let's code gradient box

For this, we need to create a box with some height and width and set the background to a linear gradient.

import React from "react";
import styled from "styled-components";

const GradientBoxStyle = styled.div`
  width: max(20vw, 200px);
  height: max(30vw, 300px);
  background: linear-gradient(45deg, red, blue);
  margin: 3em auto;
  border-radius: 30px;
`;

const GradientBox = (props) => (
  <GradientBoxStyle
  />
);

export default GradientBox;

Enter fullscreen mode Exit fullscreen mode

Let's use it inside the App component

    <GradientContainer>
      <div className="gradient_container_header">
        <h1 className="gradient_container_header_heading">
          Gradient Generator
        </h1>
        <h3 className="gradient_container_header_subheading">
          Generate your gradient
        </h3>
      </div>
      <div className="gradient_container_main">
        <div className="gradient_container_main_color_box">
          <ColorInput />

          <div className="gradient_conatiner_main_color_box_range">
            <RangeInput />
          </div>
        </div>
        <div className="gradient_container_main_gradient_box">
          <GradientBox />
        </div>
        <div className="gradient_container_main_color_box">
          <ColorInput />

          <div className="gradient_conatiner_main_color_box_range">
            <RangeInput />
          </div>
        </div>
      </div>
      <div className="gradient_container_footer">
        <h3>In Deg</h3>

        <RangeInput />

        <h3 className="gradient_container_footer_text">
          Code for the gradient that you have generated
        </h3>
        <h1 className="gradient_container_footer_code">// Code will go here</h1>
      </div>
    </GradientContainer>
Enter fullscreen mode Exit fullscreen mode

Output
Output of the above code

Now if I try to pick some color from the color picker nothing will happen the color of the gradient box will remain the same.
Obviously
because right now our gradient box has a static background. But we want to change the background of the gradient box to the color user picked which means we need to change the state of the app as the user changes the color of the color picker and the best way to deal with this scenario is to use useState hook (because I am using functional components)

What we need to do

  1. Create a variable (using useState because we also need to change the state of our app) that will store the value of the color as the user changes the color of the color picker.
  2. Pass that variable to the gradient box so that we can apply that color to the background.

Let's tackle the first part.

Create a useState hook that will store the color of the color picker.

const App = () => {
  const [gradientValues, setGradientValues] = useState({
    color1: "#bb00ff"
  });
Enter fullscreen mode Exit fullscreen mode

I have also given some default colors to this variable. This default color will be rendered when our app will be loaded for the first time.

Now let's tackle the second part.

Simply pass this variable as a prop to the GradientBox component.

        <div className="gradient_container_main_gradient_box">
          <GradientBox 
          color1 = {gradientValues.color1}/>
        </div>
Enter fullscreen mode Exit fullscreen mode

And in the GradientBox component


import React from "react";
import styled from "styled-components";

const GradientBoxStyle = styled.div`
  width: max(20vw, 200px);
  height: max(30vw, 300px);
  background: linear-gradient(45deg, red, blue);
  margin: 3em auto;
  border-radius: 30px;
`;

const GradientBox = ({
  color1
}) => (
  <GradientBoxStyle 
  color1 = {color1}
  />
);

export default GradientBox;
Enter fullscreen mode Exit fullscreen mode

Instead of using props, I destructured it using JavaScript object destructuring to use the direct value and also pass this value inside the style component so that I can access this variable inside my stylesheet.

Now set the background to the chosen color.

import React from "react";
import styled from "styled-components";

const GradientBoxStyle = styled.div`
  width: max(20vw, 200px);
  height: max(30vw, 300px);

  background: ${({
    color1,
  }) =>
    `linear-gradient(45deg, ${color1}, red)`};

  margin: 3em auto;
  border-radius: 30px;
`;

const GradientBox = ({
  color1,
}) => (
  <GradientBoxStyle
    color1={color1}
  />
);

export default GradientBox;
Enter fullscreen mode Exit fullscreen mode

Output

Output of the above code

But now if we still try to change the color of the gradient box by choosing color from color picker nothing will happen.

WHY

Because we still haven't added the color-changing functionality. We didn't tell ours react app what will happen if someone changes the color of the color picker.

Now let's discuss what we need to do to add this functionality.

  1. We need to keep listening for changes in the color input.
  2. We need to get the value of the current color the user is on.

Let's tackle the first problem

We are going to use the onChange property to keep listening for any change in the ColorInput.

const ColorInput = ({
  colorInputChangeHandler
 }) => (
  <ColorInputStyle
    type="color"
    onChange={(e) => colorInputChangeHandler(e)}
  />
);
export default ColorInput;
Enter fullscreen mode Exit fullscreen mode

colorInputChangeHandler as the name itself suggests is going to tell ours react app what will happen if we change the color of the input. We are passing these functions as a prop. And also we need the current color the user is on therefore I am passing e, which will contain all the information related to ColorInput.

Now let's create this function and pass this function to the ColorInput component

  const colorInputChangeHandler = (e) => {
    const color = e.target.value;
    setGradientValues({
      ...gradientValues,
      color1: color
    })
  };
Enter fullscreen mode Exit fullscreen mode

Here I am storing the value of the current color to the color variable and updating the state with the value of the new color that the user selected.

"...gradientValue" is a spread operator if you don't know about it let me give you a brief intro to it.

...gradientValue will get all the previous values stored in the gravientValue. Then we can update whatever value we want without changing the object.

Consider this example

gradientValue = {
    color1: "color 1 value",
    color2: "color 2 value"
}

// without using spread operator
setGradientValue({
    color1: "color 1 change value"
})

console.log(gradientValue)
// output
/*
  gradientValue = {
        color1: "color 1 change value"
}

property color 2 is gone.
setGradientValue set { color1: "color 1 change value" } this object to the gradientValue
*/

// using spread operator
setGradientValue({
    ...gradientValue
    color1: "color 1 change value"
})

console.log(gradientValue)
// output
/*
  gradientValue = {
        color1: "color 1 change value",
        color2: "color 2 value"
}
Enter fullscreen mode Exit fullscreen mode

Right now gradientValue contains only one value so you will not notice the difference but later we are going to add more property to it.

output of the above code

When you load the page the starting color in the gradient box is #bb00ff but the starting color in the color input is black. We need to fix that. This problem can be easily fixed by setting the value property of the color input to the current color of the gradient box.

Pass the current value of the color to the ColorInput

<div className="gradient_container_main_color_box">
          <ColorInput
            colorValue={gradientValues.color1}
            colorInputChangeHandler={(e) => colorInputChangeHandler(e)}
          />
Enter fullscreen mode Exit fullscreen mode

and in the ColorInput

const ColorInput = ({ 
  colorValue, 
  colorInputChangeHandler }) => (
  <ColorInputStyle
    type="color"
    value={colorValue}
    onChange={(e) => colorInputChangeHandler(e)}
  />
);
Enter fullscreen mode Exit fullscreen mode

Now when you load the page you will get

output of the above code

Now with the same logic let's add functionality to other color input

First let's create the variable to store the current color value

  const [gradientValues, setGradientValues] = useState({
    color1: "#bb00ff",
    color2: "#00ffee",
  });
Enter fullscreen mode Exit fullscreen mode

Pass all this value to the second ColorInput

//Second color input
          <ColorInput
            colorValue={gradientValues.color2}
            colorInputChangeHandler={(e) => colorInputChangeHandler(e)}
          />
Enter fullscreen mode Exit fullscreen mode

and also pass this value to the GradientBox

          <GradientBox
            color1={gradientValues.color1}
            color2={gradientValues.color2}
          />
Enter fullscreen mode Exit fullscreen mode

and in the GradientBox

import React from "react";
import styled from "styled-components";

const GradientBoxStyle = styled.div`
  width: max(20vw, 200px);
  height: max(30vw, 300px);
  background: ${({
    color1,
    color2,
  }) =>
    `linear-gradient(45deg, ${color1}, ${color2})`};
  margin: 3em auto;
  border-radius: 30px;
`;

const GradientBox = ({
  color1,
  color2,
}) => (
  <GradientBoxStyle
    color1={color1}
    color2={color2}
  />
);

export default GradientBox;

Enter fullscreen mode Exit fullscreen mode

Output

output of the above code

But there is a problem. Go on and try to change the color of the gradient box by changing the color of the second color input.

above Problem

On changing the value of the second color input, the value of the first color input changes.

and why's thatoutput of the above code

Because no matter what color input we are changing, we are calling the same function (colorInputChangeHandler) which is only changing the color of the color1.

  const colorInputChangeHandler = (e) => {
    const color = e.target.value;
      setGradientValues({
        ...gradientValues,
        color1: color
      });
  };
Enter fullscreen mode Exit fullscreen mode

There are two ways to solve the above problem

  1. To create a new function and pass that in the second color input
  2. We can use the name property of the input tag in HTML to identify which color input is currently active and change the value of color accordingly

I am going to follow the second approach. I don't want to create another function that performs the same thing. Because later we are going to add functionality to our range input and there are a total of 3 of them and I am not gonna create 3 separate functions for them.

Now let's add the name property to our color input

const ColorInput = ({ colorValue, 
  colorInputChangeHandler, 
  inputName }) => (
  <ColorInputStyle
    type="color"
    value={colorValue}
    name={inputName}
    onChange={(e) => colorInputChangeHandler(e)}
  />
);
export default ColorInput;
Enter fullscreen mode Exit fullscreen mode

Pass the inputName value to our colorInput

<div className="gradient_container_main">
        <div className="gradient_container_main_color_box">
          <ColorInput
            colorValue={gradientValues.color1}
            inputName="color1"
            colorInputChangeHandler={(e) => colorInputChangeHandler(e)}
          />
          <div className="gradient_conatiner_main_color_box_range">
            <RangeInput
            />
          </div>
        </div>
        <div className="gradient_container_main_gradient_box">
          <GradientBox
            color1={gradientValues.color1}
            color2={gradientValues.color2}
          />
        </div>
        <div className="gradient_container_main_color_box">
          <ColorInput
            colorValue={gradientValues.color2}
            inputName="color2"
            colorInputChangeHandler={(e) => colorInputChangeHandler(e)}
          />
          <div className="gradient_conatiner_main_color_box_range">
            <RangeInput
            />
          </div>
        </div>
      </div>
Enter fullscreen mode Exit fullscreen mode

Now using simple if and else statement we can check which color value we need to change.

const colorInputChangeHandler = (e) => {
    const name = e.target.name;
    const color = e.target.value;
    if (name === "color1") {
      setGradientValues({
        ...gradientValues,
        color1: color
      });
    } else if (name === "color2") {
      setGradientValues({
        ...gradientValues,
        color2: color
      });
    }
  };
Enter fullscreen mode Exit fullscreen mode

And finally the work of the color input is done.

Celebrate

Adding functionality to range Input

Its functionality is the same as the Color Input.

  1. Add some variables to keep track of the change made.
  2. Add some props to our range input
  3. Add a function that changes the state.
  4. Pass that variable to the gradient box for changing the background.

Let's discuss these points one by one

What variable do we need?
For changing color 1 percentage, for changing color 2 percent, and for changing the angle of a linear gradient.
Let's add these variables to our state

  const [gradientValues, setGradientValues] = useState({
    angle: 45,
    color1: "#bb00ff",
    color2: "#00ffee",
    color1Percentage: 50,
    color2Percentage: 50
  });
Enter fullscreen mode Exit fullscreen mode

Let's add some props to our range input

const RangeInput = ({
  start,
  end,
  rangeValue,
  rangeName,
  rangeInputChangeHandler
}) => (
  <RangeInputStyle
    type="range"
    min={start}
    max={end}
    value={rangeValue}
    name={rangeName}
    onChange={(e) => rangeInputChangeHandler(e)}
  />
);
export default RangeInput;
Enter fullscreen mode Exit fullscreen mode

start and end will be the minimum and maximum values respectively. For example in color1Percentage start = 0 and end = 100 and in angle start = 0 and end = 360

name is provided to identify which range input is triggered (as we discuss in color input)

when the range is changed rangeInputChangeHandler will be triggered.

Let's add functionality to our range input.

const rangeInputChangeHandler = (e) => {
    const value = e.target.value;
    const name = e.target.name;
    if (name === "angle") {
      setGradientValues({
        ...gradientValues,
        angle: value
      });
    } else if (name === "color1Percentage") {
      setGradientValues({
        ...gradientValues,
        color1Percentage: value
      });
    } else if (name === "color2Percentage") {
      setGradientValues({
        ...gradientValues,
        color2Percentage: value
      });
    }
  };
Enter fullscreen mode Exit fullscreen mode

Pass all the value to range input and gradient box

<GradientContainer>
      <div className="gradient_container_header">
        <h1 className="gradient_container_header_heading">
          Gradient Generator
        </h1>
        <h3 className="gradient_container_header_subheading">
          Generate your gradient
        </h3>
      </div>
      <div className="gradient_container_main">
        <div className="gradient_container_main_color_box">
          <ColorInput
            colorValue={gradientValues.color1}
            inputName="color1"
            colorInputChangeHandler={(e) => colorInputChangeHandler(e)}
          />
          <div className="gradient_conatiner_main_color_box_range">
            <RangeInput
              start={0}
              end={100}
              rangeName="color1Percentage"
              rangeValue={gradientValues.color1Percentage}
              rangeInputChangeHandler={(e) => rangeInputChangeHandler(e)}
            />
          </div>
        </div>
        <div className="gradient_container_main_gradient_box">
          <GradientBox
            color1={gradientValues.color1}
            color2={gradientValues.color2}
            angle={gradientValues.angle}
            color1Percentage={gradientValues.color1Percentage}
            color2Percentage={gradientValues.color2Percentage}
          />
        </div>
        <div className="gradient_container_main_color_box">
          <ColorInput
            colorValue={gradientValues.color2}
            inputName="color2"
            colorInputChangeHandler={(e) => colorInputChangeHandler(e)}
          />
          <div className="gradient_conatiner_main_color_box_range">
            <RangeInput
              start={0}
              end={100}
              rangeName="color2Percentage"
              rangeValue={gradientValues.color2Percentage}
              rangeInputChangeHandler={(e) => rangeInputChangeHandler(e)}
            />
          </div>
        </div>
      </div>
      <div className="gradient_container_footer">
        <h3>In Deg</h3>
        <RangeInput
          start={0}
          end={360}
          rangeValue={gradientValues.angle}
          rangeName="angle"
          rangeInputChangeHandler={(e) => rangeInputChangeHandler(e)}
        />
        <h3 className="gradient_container_footer_text">
          Code for the gradient that you have generated
        </h3>
        <h1 className="gradient_container_footer_code">
          Code will go here
        </h1>
      </div>
    </GradientContainer>
Enter fullscreen mode Exit fullscreen mode

Use this value inside the GradientBox

import React from "react";
import styled from "styled-components";

const GradientBoxStyle = styled.div`
  width: max(20vw, 200px);
  height: max(30vw, 300px);
  background: ${({
    angle,
    color1,
    color2,
    color1Percentage,
    color2Percentage
  }) =>
    `linear-gradient(${angle}deg, ${color1} ${color1Percentage}%, ${color2} ${color2Percentage}%)`};
  margin: 3em auto;
  border-radius: 30px;
`;

const GradientBox = ({
  color1,
  color2,
  angle,
  color1Percentage,
  color2Percentage
}) => (
  <GradientBoxStyle
    color1={color1}
    color2={color2}
    angle={angle}
    color1Percentage={color1Percentage}
    color2Percentage={color2Percentage}
  />
);

export default GradientBox;
Enter fullscreen mode Exit fullscreen mode

Finally display the linear gradient code

Using all the variable we created in the useState we can easily generate the code

        <h1 className="gradient_container_footer_code">
          linear-gradient({gradientValues.angle}deg, {gradientValues.color1}{" "}
          {gradientValues.color1Percentage}%, {gradientValues.color2}{" "}
          {gradientValues.color2Percentage}%);
        </h1>
Enter fullscreen mode Exit fullscreen mode

as the value changes the state will be updated.

and that's it. We got our linear gradient generator.

Top comments (0)