Very simple way to render star rating
Tags: react, webdev, typescript, webcomponents
Published: 2022-07-03 09:43:46

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4q99jqa03qdft479k6o9.png)

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:

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

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

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

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

  //...
```

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.

```javascript
  //...
  
  const width = filling * 100 + '%';

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

Next I need `StarRating` component.

The component have one props too.

```typescript
type Props = {
  value: number;
};
```

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

```typescript
export const StarRating = ({ value }: Props) => (
  <div className={styles.rating}>
    {Array.from(Array(5)).map((_, index) => <Star />)}
  </div>
);
```
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`.

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

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

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

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

The filling props calculated as:

```typescript
const filling = value - index;
```

Fill `StarRating` component looks like this

```typescript
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>
);
```

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