<header class="big-header">
<h1>Rating Star Widget <br>with ReactJS</h1>
<p>A simple rating widget using <b>ReactJS</b> and <b>FontAwesome (5!)</b> icons.</p>
<p class="sub">Last I created the same widget using jQuery, it is one of my most popular pen. I thought why not create the same using React. Here it is.</p>
</header>
<div id="widget">
</div>
<footer id="credits">
<p class="note"><b>Note:</b> This widget is not accessible, if you wish to use it in a real life application please do consider taking a look at <a href="https://reactjs.org/docs/accessibility.html" target="_blank">ReactJS Accessibility Guide</a>. Also, check an accessible version of the widget here: <a href="https://codepen.io/depy/details/rJQyNK/" target="_blank">Accessible version</a></p>
<p style="font-size: 14px;">Created with <i class="fas fa-heart" style="color: tomato;"></i> by Deepak Kamat (<a href="https://twitter.com/xxxdepy" target="_blank">@xxxdepy</a>)</p>
</footer>
body {
font-family:"Open Sans", Helvetica, Arial, sans-serif;
color:#555;
max-width:680px;
margin:0 auto;
padding:0 20px;
}
* {
-webkit-box-sizing:border-box;
-moz-box-sizing:border-box;
box-sizing:border-box;
}
*:before, *:after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
a {
color: tomato;
text-decoration: none;
}
a:hover {
color: #2196f3;
}
/*----------------------------
BIG HEADER
------------------------------*/
.big-header {
padding: 2em 0;
position: relative;
text-align: center;
}
.big-header:after {
content:"";
display:block;
height:1px;
background:#eee;
position:absolute;
left:30%; right:30%;
bottom: 0;
}
.big-header h1 {
font-size:2.75em;
font-weight:300;
margin-bottom:0.2em;
}
.big-header p {
font-size: 16px;
}
.big-header p.sub {
font-size: 12px;
color: #9999;
}
.note {
margin: 20px 0;
padding: 10px;
color: #888;
background-color: #fefefe;
font-size: 12px;
border-left: 5px solid tomato;
}
/* Widget Container */
#widget {
position: relative;
padding: 20px 0;
margin: 20px 0;
border: 1px solid #eee;
border-width: 0;
}
/*----------------------------
Rating Star Widget Style
-----------------------------*/
.rating-stars {
position: relative;
display: block;
text-align: center;
}
.rating-stars .star {
display: inline-block;
padding: 0 5px;
font-size: 2.5em;
color: #ccc;
transition: 0.1s all ease-in-out;
transform: scale(0.8);
}
.rating-stars .star:hover,
.rating-stars .star.semi-active {
color: #ffd73e;
transform: scale(1);
}
.rating-stars .star.active {
color: #FF9800;
transform: scale(1);
}
/* Rating Message */
.after-rating-message {
display: none;
text-align: center;
margin: 20px auto;
padding: 20px 20px;
background-color: #f7f7f7;
opacity: 0;
transition: 0.2s all ease-in-out;
}
.after-rating-message.show {
display: block;
opacity: 1;
}
function Star( props ){
return (
<div className={`star ${(props.value == 0) ? 'semi-active' : ''} ${(props.position <= props.rated) ? 'active' : ''} `}
onMouseEnter={ props.onMouseEnter }
onMouseLeave={ props.onMouseLeave }
onClick={ props.onClick }
>
<i className="fas fa-star"></i>
</div>
);
}
function Rating( props ){
const messages = {
"1": "Oh. Sorry you had a bad experience :( ",
"2": "We will try to improve.",
"3": "Appreciate it!",
"4": "Thank you!",
"5": "You're Awesome!"
};
let rating = props.rating;
return(
<div className={"after-rating-message " + ((rating > 0) ? 'show': '')} >
<span>You rated this {rating} star{rating > 1 ? 's' : ''}</span>
<br/>
<span>{ messages[rating] }</span>
</div>
);
}
class RatingWidget extends React.Component {
constructor( props ) {
super( props );
this.state = {
stars: Array(5).fill(-1),
rated: 0
};
}
handleMouseOver( i ) {
let currentRating = this.state.rated;
if ( currentRating > 0 ) {
const hoverRatedStars = this.state.stars.slice();
_.fill( hoverRatedStars, 0, currentRating, i );
this.setState({ stars: hoverRatedStars });
}
else {
const hoverStars = Array(5).fill(-1);
_.fill( hoverStars, 0, 0, (i+1) );
this.setState({ stars: hoverStars});
}
}
handleMouseOut() {
let currentRating = this.state.rated;
if ( currentRating > 0) {
const resetRatedStars = this.state.stars.slice();
_.fill( resetRatedStars, -1, currentRating, resetRatedStars.length );
this.setState({stars: resetRatedStars});
}
else {
const resetStars = this.state.stars.slice();
_.fill( resetStars, -1, 0, resetStars.length );
this.setState({stars: resetStars});
}
}
handleClick( i ) {
const clickedStar = this.state.stars.slice();
_.fill( clickedStar, 1, 0, i );
_.fill( clickedStar, 1, i, clickedStar.length );
this.setState({
stars: clickedStar,
rated: i
});
}
handleRating( rating ){
return (<Rating rating={this.state.rated} />)
}
renderStar( i ){
return (
<Star
position={i}
value={this.state.stars[i]}
rated={this.state.rated}
onMouseEnter={ () => this.handleMouseOver(i) }
onMouseLeave={ () => this.handleMouseOut() }
onClick={ () => this.handleClick(i) }
/>
);
}
render(){
return (
<div className='rating-stars-widget-outer'>
<div className='rating-stars'>
{this.renderStar(1)}
{this.renderStar(2)}
{this.renderStar(3)}
{this.renderStar(4)}
{this.renderStar(5)}
</div>
{this.handleRating( this.state.rated )}
</div>
);
}
}
ReactDOM.render(<RatingWidget />, document.getElementById("widget"));
View Compiled