DEV Community

Cover image for How to make a Rating Component with React & Typescript
Md Mostafizur Rahman
Md Mostafizur Rahman

Posted on

How to make a Rating Component with React & Typescript

Creating a custom rating component in React using Typescript looks like intimidating sometimes, but it's pretty simple to do. In this article, I will show you how to create a custom Rating component using React & Typescript step by step.

Custom Rating Component

To start, you will need to create a new React project and make sure that TypeScript is set up. You can use create-react-app or vite to quickly set up a new project with TypeScript.

Once you have your project set up, create a new file for your rating component and name it like "Rating.tsx" and follow these steps one by one.

Step 1: Define the props for the component. We will use the following props to customize our components.

  • className: a className that can be passed to customize the styling of the component.
  • count: the number of stars to display in the rating.
  • value: the current value of the rating.
  • color: the color of the stars when they are not being hovered over or clicked on.
  • hoverColor: the color of the stars when they are being hovered over.
  • activeColor: the color of the stars when they are being clicked on.
  • size: the size of the stars in pixels.
  • edit: a boolean value that determines whether the rating can be edited by the user.
  • isHalf: a boolean value that determines whether the rating allows for half-star increments.
  • onChange: a callback function that is called when the rating is changed.
  • emptyIcon: an icon to be used for empty stars.
  • halfIcon: an icon to be used for half stars.
  • fullIcon: an icon to be used for full stars.

In your Rating.tsx file:

interface RatingProps {
  className?: string;
  count: number;
  value: number;
  color?: string;
  hoverColor?: string;
  activeColor?: string;
  size?: number;
  edit?: boolean;
  isHalf?: boolean;
  onChange?: (value: number) => void;
  emptyIcon?: React.ReactElement;
  halfIcon?: React.ReactElement;
  fullIcon?: React.ReactElement;
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Define the star icon components using svg. You can also use any icon library for that.

interface IconProps {
  size?: number;
  color?: string;
}

const FullStar = ({ size = 24, color = "#000000" }: IconProps) => {
  return (
    <div style={{ color: color }}>
      <svg height={size} viewBox="0 0 24 24">
        <path
          d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"
          fill="currentColor"
        />
        <path d="M0 0h24v24H0z" fill="none" />
      </svg>
    </div>
  );
};

const HalfStar = ({ size = 24, color = "#000000" }: IconProps) => {
  return (
    <div style={{ color: color }}>
      <svg height={size} viewBox="0 0 24 24">
        <path
          d="M22 9.24l-7.19-.62L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21 12 17.27 18.18 21l-1.63-7.03L22 9.24zM12 15.4V6.1l1.71 4.04 4.38.38-3.32 2.88 1 4.28L12 15.4z"
          fill="currentColor"
        />
        <path d="M0 0h24v24H0z" fill="none" />
      </svg>
    </div>
  );
};

const EmptyStar = ({ size = 24, color = "#000000" }: IconProps) => {
  return (
    <div style={{ color: color }}>
      <svg height={size} viewBox="0 0 24 24">
        <path
          d="M22 9.24l-7.19-.62L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21 12 17.27 18.18 21l-1.63-7.03L22 9.24zM12 15.4l-3.76 2.27 1-4.28-3.32-2.88 4.38-.38L12 6.1l1.71 4.04 4.38.38-3.32 2.88 1 4.28L12 15.4z"
          fill="currentColor"
        />
        <path d="M0 0h24v24H0z" fill="none" />
      </svg>
    </div>
  );
};

Enter fullscreen mode Exit fullscreen mode

Step 4: Now, define the rating component, destruct the props with some default values.

const Rating: React.FC<RatingProps> = ({
  className,
  count,
  value,
  color = "#ffd700",
  hoverColor = "#ffc107",
  activeColor = "#ffc107",
  size = 30,
  edit = false,
  isHalf = true,
  onChange,
  emptyIcon = <EmptyStar />,
  halfIcon = <HalfStar />,
  fullIcon = <FullStar />
}) => {
  return <div></div>
};
Enter fullscreen mode Exit fullscreen mode

Step 5: Next, create a state for our rating component. This state will be used to track the current rating value selected by the user. We will also need to define some methods to update the state when the user interacts with the component.

const [hoverValue, setHoverValue] = useState<number | undefined>(undefined);

const handleMouseMove = (index: number) => {
  if (!edit) {
    return;
  }
  setHoverValue(index);
};

const handleMouseLeave = () => {
  if (!edit) {
    return;
  }
  setHoverValue(undefined);
};

const handleClick = (index: number) => {
  if (!edit) {
    return;
  }
  if (onChange) {
    onChange(index + 1);
  }
};
Enter fullscreen mode Exit fullscreen mode

Step 6: Now we have the props and state set up, you can start rendering the stars for the rating component. For doing this, we will need to use a loop to render the number of stars specified by the count prop. Inside the loop, we need to check whether the current star should be empty, half or full. We should also add the onMouseEnter, onMouseLeave and onClick events along with the size and color to each of these star icon components.

 const stars = [];

  for (let i = 0; i < count; i++) {
    let star: React.ReactElement;
    if (isHalf && value - i > 0 && value - i < 1) {
      star = halfIcon;
    } else if (i < value) {
      star = fullIcon;
    } else {
      star = emptyIcon;
    }

    if (hoverValue !== undefined) {
      if (i <= hoverValue) {
        star = fullIcon;
      }
    }

    stars.push(
      <div
        key={i}
        style={{ cursor: "pointer" }}
        onMouseMove={() => handleMouseMove(i)}
        onMouseLeave={handleMouseLeave}
        onClick={() => handleClick(i)}
      >
        {React.cloneElement(star, {
          size: size,
          color: i <= Number(hoverValue) ? hoverColor : i < value ? activeColor : color,
        })}
      </div>
    );
  }

 return <div className={`rating ${className}`}>{stars}</div>;
Enter fullscreen mode Exit fullscreen mode

Step 7: Finally, export the component so that it can be used in other parts of application. Here is an example use of our rating component:

import React from "react";
import Rating from "./Rating";

export default function App() {
  const [rating, setRating] = React.useState(0);

  return (
    <div className="App">
      <div>
        <h3>Editable</h3>
        <Rating
          count={5}
          value={rating}
          edit={true}
          onChange={(value) => setRating(value)}
        />
        <p>
          <b>Value: </b>
          {rating} stars
        </p>
      </div>
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

Check out a demo of this component in action by visiting this link CodeSandbox

Top comments (0)