DEV Community

Vladimir Schneider
Vladimir Schneider

Posted on • Edited on

Very simple way to render star rating

Hi there πŸ‘‹πŸΌ

That is easy way to create star-rating component on React. The component will not support submit rating, it's about visualization of rating using stars only.

Image description

I did split solution on two components: <Star /> and <StarRating />.

Start with <Star /> component. Let's describe component's rules:

  1. Component can be on and off. It's about filled or empty star.
  2. If the value is not binary (on/off) component should render partially filled star

It's our component conditions.

The component will be have only one props:



type Props = {
  // value from 0 to 1
  filling?: number;
};


Enter fullscreen mode Exit fullscreen mode

Let's start with first, it's easy.



export const Star = ({ filling }: Props) => {
  if (typeof filling === 'undefined' || filling === 1) {
    return (
      <FilledStar />
    );
  }

  if (filling === 0) {
    return (
      <EmptyStar />
    );
  }

  //...


Enter fullscreen mode Exit fullscreen mode

This is a binary story. Go to next.

I need overlap empty star using filled star. I use container for stars and doing each star absolutely positioned. Filled star will have overflow: hidden and using filling props I can change width of star to control visibility.



  //...

  const width = filling * 100 + '%';

  return (
    <div className={styles.star}>
      <div className={styles.fill} style={{ width }}>
        <FilledStar />
      </div>
      <div className={styles.empty}>
        <EmptyStar />
      </div>
    </div>
  );
};


Enter fullscreen mode Exit fullscreen mode

Next I need StarRating component.

The component have one props too.



type Props = {
  value: number;
};


Enter fullscreen mode Exit fullscreen mode

So, let's write a simple component which render five stars.



export const StarRating = ({ value }: Props) => (
  <div className={styles.rating}>
    {Array.from(Array(5)).map((_, index) => <Star />)}
  </div>
);


Enter fullscreen mode Exit fullscreen mode

I think it's very easy. All that's left is understand when I should render filled star, empty and partial filled.

I should always render filled star if serial number of the star less or equal than rounded in down value.



if (starSerialNumber <= Math.floor(value) >=) {
  //...


Enter fullscreen mode Exit fullscreen mode

And I should render empty star if serial number of the star more than rounded in up value.



if (starSerialNumber > Math.ceil(value) >=) {
  //...


Enter fullscreen mode Exit fullscreen mode

When serial number of the star is equal rounded in up value I should render partial filled star.

The filling props calculated as:



const filling = value - index;


Enter fullscreen mode Exit fullscreen mode

Fill StarRating component looks like this



export const StarRating = ({ value }: Props) => (
  <div className={styles.rating}>
    {Array.from(Array(5)).map((_, index) => {
      const starSerialNumber = index + 1;

      if (starSerialNumber <= Math.floor(value)) {
        return (
          <div key={starSerialNumber} className={styles.star}>
            <Star />
          </div>
        );
      }

      if (starSerialNumber > Math.ceil(value)) {
        return (
          <div key={starSerialNumber} className={styles.star}>
            <Star filling={0} />
          </div>
        );
      }

      const filling = value - index;

      return (
        <div key={starSerialNumber} className={styles.star}>
          <Star filling={filling} />
        </div>
      );
    })}
  </div>
);


Enter fullscreen mode Exit fullscreen mode

Thank you that have read the post. Have a good day.

Top comments (1)

Collapse
 
dannyengelman profile image
Danny Engelman • Edited

And without React, it is only 20 lines of JavaScript:

Twinkle, Twinkle, Web Component Star