How to make a Feedback Component to seamlessly collect reviews in React.JS
Tags: react, webdev, javascript, ux
Published: 2021-09-17 18:08:56

For a business, customer feedback happens to be one of the most reliable ways to know how they are doing. As Developer, we should try and make this process as intuitive and simple as possible.

This article aims to explain, how we could develop a customer feedback component using React, Lottie Web & Framer Motion. So let's get started with it then! 😉


### Project Initialization  

```
npx create-react-app emoji-feedback
``` 


### Install Dependencies


- [React Lottie](https://www.npmjs.com/package/react-lottie) for integrating Lottie animations
- [Framer Motion](https://www.npmjs.com/package/framer-motion) for micro-interactions
- [Styled Components](https://www.npmjs.com/package/styled-components) for styling needs



```
yarn add react-lottie framer-motion styled-components
```


### Animated Emojis

To get the emojis to animate, we have 2 options:
1.  Animated emoji pack (Mostly Paid)
2. Lottie Animations (Free & Paid)

I went with the 2nd option for this one. The animations used in this component are by [jkkim0124](https://lottiefiles.com/jkkim0124). Simply select your favorite animations and place them under the `src/lotties` folder.



### Component Breakdown

![Breakdown of the component](https://cdn.hashnode.com/res/hashnode/image/upload/v1628096449063/i4i5KCiSA.jpeg)



### App Component

Call the Emoji Feedback component along with the necessary state props.

```
// path: src/App.js

// React 
import { useState } from "react";

// External
import styled from "styled-components";

// Components
import EmojiFeedback from "./components/EmojiFeedback";

const AppStyles = styled.div`
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  background-color: #f8ebe2;
`;

const App = () => {
  const [activeReaction, setActiveReaction] = useState("");
  return (
    <AppStyles>
      <EmojiFeedback
        activeReaction={activeReaction}
        setActiveReaction={setActiveReaction}
      />
    </AppStyles>
  );
};

export default App;
``` 



### Constants

Declare an array containing strings of the various supported reactions.

```
// path: src/components/EmojiFeedback/data.js

const reactions = ["Aweful", "Bad", "Ok Ok", "Good", "Amazing"];

export { reactions };
```


### Emoji Feedback Component

Loop through the reactions and then call the Emoji component for every reaction.


```
// path: src/components/EmojiFeedback/index.jsx

// External
import styled from "styled-components";

// Components
import Emoji from "./Emoji";
import { Flex } from "../../styles/globalStyles";

// Reactions array
import { reactions } from "./data";

const Card = styled.div`
  width: 800px;
  height: 500px;
  background-color: #fff;
  border-radius: 33px;
  padding: 44px 48px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);

  @media only screen and (max-width: 930px) {
    width: 80%;
  }
`;

const Heading = styled.h2`
  font-size: 42px;
  font-weight: bold;
  margin: 0;
  color: #000;
  font-family: Plus Jakarta Sans Bold;
`;

const Content = styled(Flex)`
  height: 452px;
  position: relative;
`;

const Emojis = styled(Flex)`
  top: 30%;
`;

const Button = styled.button`
  background-color: ${props => (props.isSelected ? "#000" : "#ccc")};
  cursor: ${props => (props.isSelected ? "pointer" : "not-allowed")};
  border: none;
  color: #fff;
  padding: 19.5px 107.3px;
  border-radius: 19px;
  font-family: Plus Jakarta Sans Medium;
  font-size: 24px;
  user-select: none;
  position: absolute;
  bottom: 0;
`;

const EmojiFeedback = ({ activeReaction, setActiveReaction }) => {
  return (
    <Card>
      <Heading>How was your experience?</Heading>
      <Content column>
        <Emojis>
          {reactions.map(reaction => (
            <Emoji
              reaction={reaction}
              key={reaction}
              isSelected={activeReaction === reaction}
              setActiveReaction={setActiveReaction}
            />
          ))}
        </Emojis>
        <Button isSelected={!!activeReaction}>Submit</Button>
      </Content>
    </Card>
  );
};

export default EmojiFeedback;
```



### Emoji Component
The emoji component is being used to render a single emoji.

```
// path: src/components/EmojiFeedback/Emoji.jsx

// External
import Lottie from "react-lottie";
import { motion } from "framer-motion";
import styled from "styled-components";

// Helper for handling lottie animation data
import selectAnimationData from "../../lotties";

const EmojiWrapper = styled(motion.div)`
  cursor: pointer;
  margin: 0 12px;
  position: relative;
`;

const EmojiLabel = styled.p`
  text-align: center;
  position: absolute;
  bottom: -32px;
  left: 50%;
  transform: translate(-50%, -50%);
  font-family: Plus Jakarta Sans Bold;
  font-size: 16px;
  user-select: none;
`;

// Constants for emoji's scale during different states
const NORMAL_SCALE = 1;
const HOVERED_SCALE = 1.3;
const SELECTED_SCALE = 1.5;

const Emoji = ({ reaction, isSelected, setActiveReaction }) => {
  // Initialize the animation options as per the reaction
  const animationOptions = {
    loop: true,
    autoplay: false,
    animationData: selectAnimationData(reaction),
    rendererSettings: {
      preserveAspectRatio: "xMidYMid slice",
    },
  };

  // Update state on the click of reaction
  const handleClick = () => {
    if (isSelected) {
      setActiveReaction("");
    } else {
      setActiveReaction(reaction);
    }
  };

  return (
    <EmojiWrapper
      whileHover={{
        scale: isSelected ? SELECTED_SCALE : HOVERED_SCALE,
      }}
      animate={{
        scale: isSelected ? SELECTED_SCALE : NORMAL_SCALE,
      }}
      onClick={handleClick}
    >
      <Lottie
        options={animationOptions}
        height={100}
        width="80%"
        isStopped={!isSelected}
        isClickToPauseDisabled
      />
      {isSelected && <EmojiLabel>{reaction}</EmojiLabel>}
    </EmojiWrapper>
  );
};

export default Emoji;

```



### Conclusion

And there we have it, the emoji feedback component is ready. The [Code](https://github.com/parmeet1402/internal-component-collection/tree/main/emoji-feedback) is available on Github. Would love to hear your valuable feedback in the comments down below.

See you guys 👋🏻&nbsp; in the next article of this Component series!


Happy coding & Stay safe! ✨

Follow me on [Twitter](https://twitter.com/parmeetasija) & [Instagram](https://www.instagram.com/parmeetasija/) for more!

This article can also be read on my [website](https://www.parmeetasija.com/blog/how-to-make-a-feedback-component-to-seamlessly-collect-reviews-in-reactjs)!