This is what we are going to code.
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
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>
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.
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;
}
`;
How to code color picker
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;
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>
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;
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;
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;
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>
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;
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>
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.
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
- 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.
- 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"
});
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>
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;
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;
Output
But now if we still try to change the color of the gradient box by choosing color from color picker nothing will happen.
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.
- We need to keep listening for changes in the color input.
- 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;
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
})
};
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"
}
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.
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)}
/>
and in the ColorInput
const ColorInput = ({
colorValue,
colorInputChangeHandler }) => (
<ColorInputStyle
type="color"
value={colorValue}
onChange={(e) => colorInputChangeHandler(e)}
/>
);
Now when you load the page you will get
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",
});
Pass all this value to the second ColorInput
//Second color input
<ColorInput
colorValue={gradientValues.color2}
colorInputChangeHandler={(e) => colorInputChangeHandler(e)}
/>
and also pass this value to the GradientBox
<GradientBox
color1={gradientValues.color1}
color2={gradientValues.color2}
/>
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;
Output
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.
On changing the value of the second color input, the value of the first color input changes.
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
});
};
There are two ways to solve the above problem
- To create a new function and pass that in the second color input
- 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;
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>
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
});
}
};
And finally the work of the color input is done.
Adding functionality to range Input
Its functionality is the same as the Color Input.
- Add some variables to keep track of the change made.
- Add some props to our range input
- Add a function that changes the state.
- 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
});
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;
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
});
}
};
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>
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;
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>
as the value changes the state will be updated.
and that's it. We got our linear gradient generator.
Top comments (0)