<header>
<span>☆</span>
<h1>Interactive Star Rating</h1>
<span>☆</span>
</header>
<main>
<div id="rating-card">
<div class="card front">
<h2>Please Rate Us</h2>
<div id="emoticon-container"> </div>
<p id="satisfaction-text"> </p>
<div id="rating-component-container">
<div class="filled-stars">
<span>★</span>
<span>★</span>
<span>★</span>
<span>★</span>
<span>★</span>
</div>
<div id="blank-slider"></div>
<div class="empty-stars">
<span>☆</span>
<span>☆</span>
<span>☆</span>
<span>☆</span>
<span>☆</span>
</div>
</div>
<input type="number" id="val" step="0.1" min="0" max="10" placeholder="1 - 10">
<button id="wr-btn">Write Review</button>
</div>
<div class="card back">
<span id="back-btn">⇦</span>
<h2>Write Review</h2>
<p>Please share your thoughts about our app, so we can serve you better.</p>
<textarea id="review-field" placeholder="Write a review..." ></textarea>
<button id="rate-us">Rate Us</button>
</div>
</div>
<div class="sent">
<h2> Review Sent! </h2>
<p>Thank you for rating us.</p>
<button id="go-back-btn">Go Back</button>
</div>
</main>
:root{
--lightBlue: #43a6c6;
--darkBlue: #03000f;
--darkGray: #333;
--starSize: 3.5em;
}
html{
background-color: var( --darkBlue);
color: whitesmoke;
}
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
header{
display: flex;
justify-content: space-between;
padding: 25px;
letter-spacing: 2px;
position: sticky;
top: 0;
z-index: 2;
border-bottom: 2px solid ;
background-color: var( --darkBlue);
text-shadow: 3px 3px 5px var(--lightBlue);
box-shadow: 10px 10px 20px -10px var(--lightBlue);
}
h1{
font-size: 2.5em;
}
header > span{
font-size: 25px;
color: #ffee00;
}
main{
min-height: 90vh;
display: grid;
place-items: center;
perspective: 800px;
}
#rating-card{
position: relative;
box-shadow: 1px 1px 30px -1px var(--lightBlue);
border-radius: 20px;
transform-style: preserve-3d;
transition: 2s;
min-width: 250px;
}
.flipped{
transform: rotateY(180deg);
}
.card{
display: grid;
place-items: center;
padding: 25px 20px 40px;
background-color: var( --darkBlue);
border-radius: 20px;
}
.front{
backface-visibility: hidden;
}
.p-events{
pointer-events: none;
}
.back{
height: 100%;
position: absolute;
top: 0;
left:0;
z-index: -1;
transform: rotateY(180deg);
pointer-events: none;
}
#back-btn{
color: var(--lightBlue);
position: absolute;
top: 10px;
left:12px;
font-weight: 900;
font-size: 25px;
cursor: pointer;
}
#back-btn:hover {
transform: scale(1.2);
}
p{
padding:10px;
color:#999;
}
.back textarea{
border-radius: 10px;
background-color: transparent;
padding: 10px;
height: 100px;
color: #ccc;
width: 90%;
outline: none;
border: 2px solid var(--darkGray);
resize:none;
letter-spacing: 1.5px;
overflow: hidden;
font-weight: 100;
font-size: 12px;
}
h2{
text-shadow: 1px 1px 3px var(--lightBlue);
margin-bottom: 10px;
}
#emoticon-container{
font-size: var( --starSize);
margin-bottom: 10px;
}
#rating-component-container{
position: relative;
overflow: hidden;
cursor: pointer;
user-select: none;
}
.filled-stars{
background-image: linear-gradient(to right, red 5%, yellow, #00ff00);
background-clip: text;
-webkit-background-clip: text;
transform: scale(1);
}
.filled-stars > span{
font-size: var( --starSize);
color: transparent;
}
#blank-slider{
background-color: var( --darkBlue);
position: absolute;
height: 100%;
right: 0;
top: 0;
width: 100%;
transition: 3s;
}
.empty-stars{
position: absolute;
top: 0;
right: 0;
height: 100%;
width: 100%;
transform: scale(1);
transition: 1s;
}
.empty-stars > span{
color: var(--darkGray);
font-size: var( --starSize);
cursor: pointer;
}
#val{
background-color: transparent;
color: aliceblue;
outline: none;
padding: 8px;
margin-top: 15px;
letter-spacing: 2px;
font-weight: 700;
border-radius: 10px;
border: 2px solid var(--darkGray);
width: 80%;
}
#val:hover{
border: 2px solid var(--lightBlue);
}
.sent {
display: none;
place-items: center;
}
button{
margin-top: 30px;
border-radius: 10px;
padding: 10px;
background-color: var(--lightBlue);
border:none;
font-size: .9em;
font-weight: 600;
}
.back>textarea:hover, button:hover{
box-shadow: 1px 1px 20px -1px var(--lightBlue);
}
/* Media query for mobile phones */
@media screen and (max-width: 767px) {
:root{
--starSize: 2.5em;
}
h1, h2{
font-size: 1.2em;
}
.back > p, #satisfaction-text, button{
font-size: .7em;
}
}
const blankSlider = document.getElementById("blank-slider");
const emptyStars = document.querySelector(".empty-stars");
const val = document.getElementById("val");
const wrBtn = document.getElementById("wr-btn");
const backBtn = document.getElementById("back-btn");
const cardFront = document.querySelector(".front");
const cardBack = document.querySelector(".back");
const ratingCard = document.getElementById("rating-card");
const satisfactionTxtContainer = document.getElementById("satisfaction-text");
const goBackBtn = document.getElementById("go-back-btn");
const sentInfo = document.querySelector(".sent");
const rateUsBtn = document.getElementById("rate-us");
const reviewField = document.getElementById("review-field");
const emoticonContainer = document.getElementById("emoticon-container");
const hoverColors = ['red', 'orange', 'yellow', 'chartreuse', 'lime'];
const emoticons = ['😡', '🙁', '😐', '😊', '🤩'];
const satisfactionTxt = ['Highly Unsatisfied', 'Slightly Unsatisfied', 'feeling Indifferent', 'Quite Satisfied', 'Extremely Satisfied'];
// Function to reverse numbers within 100
function reverseValue(value) {
return 100 - value;
}
// loop through all the empty stars element
for (let i = 0; i < emptyStars.children.length; i++) {
// Change the color of hovered star on mouseenter event
emptyStars.children[i].onmouseenter = (e) => {
emptyStars.children[i].style.color = hoverColors[i];
};
// Restore the color of hovered star on mouseleave event
emptyStars.children[i].onmouseleave = (e) => {
emptyStars.children[i].style.color = "#333";
};
// Update the slider, satisfaction text, and emoticon when any of the empty stars are clicked
emptyStars.children[i].onclick = (e) => {
// changes the value of the input field to number rating for the clicked star.
val.value = i * 2 + 2;
// sets the width percentage value of the slider to the index value of the clicked star plus 1 times 20 in reverse
blankSlider.style.width = `${reverseValue((i + 1) * 20)}%`;
satisfactionTxtContainer.innerHTML = satisfactionTxt[i];
emoticonContainer.innerHTML = emoticons[i];
};
}
// Add input event listener to the input value(val) element
val.addEventListener('input', (e) => {
if (val.value < 0) {
val.value = 0;
}
// Update the slider width based on the input value
blankSlider.style.width = `${reverseValue(val.value * 10)}%`;
// Update the satisfaction text and emoticon based on the input value
const index = Math.min(Math.floor(val.value / 2 -0.5), 4);
satisfactionTxtContainer.innerHTML = index < 0 || val.value == "" ? ' ' : satisfactionTxt[index];
emoticonContainer.innerHTML = index < 0 || val.value == "" ? ' ' : emoticons[index];
})
wrBtn.onclick=()=>{
ratingCard.classList.add("flipped");
cardFront.classList.add("p-events");
cardBack.style.pointerEvents="visible";
}
backBtn.onclick=()=>{
ratingCard.classList.remove("flipped");
cardFront.classList.remove("p-events")
cardBack.style.pointerEvents="none";
}
// user's rating info object.
let userRating = {
RatingValue:"",
satisfaction: "",
review: "",
};
// store the user's rating info
rateUsBtn.onclick = () => {
ratingCard.style.display = "none";
sentInfo.style.display = "grid";
userRating.RatingValue = val.value;
userRating.satisfaction = satisfactionTxtContainer.textContent;
userRating.review = reviewField.value;
console.log(userRating);
}
goBackBtn.onclick = () => {
ratingCard.style.display = "block";
sentInfo.style.display = "none";
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.