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.
I did split solution on two components: <Star />
and <StarRating />
.
Start with <Star />
component. Let's describe component's rules:
- Component can be on and off. It's about filled or empty star.
- 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;
};
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 />
);
}
//...
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>
);
};
Next I need StarRating
component.
The component have one props too.
type Props = {
value: number;
};
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>
);
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) >=) {
//...
And I should render empty star if serial number of the star more than rounded in up value
.
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:
const filling = value - index;
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>
);
Thank you that have read the post. Have a good day.
Top comments (1)
And without React, it is only 20 lines of JavaScript:
Twinkle, Twinkle, Web Component Star