Rating v1.0.0
Allow user to evaluate content by selecting a rating, typically displayed as stars or other visual indicators.
Default Setup Anchor (Default Setup)
<fieldset class="rating">
<legend>Your rating:</legend>
<div class="rating__container">
<div class="rating__item">
<input type="radio" name="rating" value="1" id="rating-1">
<label for="rating-1"><span>1 Star</span></label>
</div>
<div class="rating__item">
<input type="radio" name="rating" value="2" id="rating-2">
<label for="rating-2"><span>2 Stars</span></label>
</div>
<div class="rating__item">
<input type="radio" name="rating" value="3" id="rating-3">
<label for="rating-3"><span>3 Stars</span></label>
</div>
<div class="rating__item">
<input type="radio" name="rating" value="4" id="rating-4">
<label for="rating-4"><span>4 Stars</span></label>
</div>
<div class="rating__item">
<input type="radio" name="rating" value="5" id="rating-5">
<label for="rating-5"><span>5 Stars</span></label>
</div>
</div>
</fieldset>/*!
Radancy Component Library: Rating
Contributor(s):
Michael "Spell" Spellacy
Dependencies: Sass
*/
.rating {
--checked-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='50' height='50' viewBox='0 0 50 50'%3e%3cpath fill='blueviolet' stroke='%23666' stroke-width='2' d='m25,1 6,17h18l-14,11 5,17-15-10-15,10 5-17-14-11h18z'/%3e%3c/svg%3e");
--max-stars: 5;
--unchecked-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='50' height='50' viewBox='0 0 50 50'%3e%3cpath fill='%23fff' stroke='%23666' d='m25,1 6,17h18l-14,11 5,17-15-10-15,10 5-17-14-11h18z'/%3e%3c/svg%3e");
border: 0;
margin: 0;
padding: 0;
width: fit-content;
&__container {
display: grid;
gap: .8em;
grid-template-columns: repeat(var(--max-stars), 1fr);
}
legend {
font-weight: bold;
margin-bottom: .5em;
}
label {
background-image: var(--unchecked-image);
background-position: center;
background-repeat: no-repeat;
background-size: contain;
display: block;
height: calc(60em/16);
margin: 0;
padding: 0;
width: calc(60em/16);
}
.active {
label {
background-image: var(--checked-image);
}
// Make sure there is always a visible focus state when cycling through input element.
input {
&:focus-visible {
+ label {
outline: 2px solid black;
outline-offset: 2px;
}
}
}
}
// Accessibly hide input and span inside label.
input, label span {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
}/*!
Radancy Component Library: Rating
Contributor(s):
Michael "Spell" Spellacy
*/
(function() {
"use strict";
// Display which Disclosure is in use via console:
console.log("%cRating%cv1.0.0", "background: #2d2d2d; color: #fff; padding: 6px 10px; border-radius: 16px 0 0 16px; font-weight: 600;" , "background: #6e00ee; color: #fff; padding: 6px 10px; border-radius: 0 16px 16px 0; font-weight: 600;");
// Select all rating items
var ratingItems = document.querySelectorAll(".rating__item");
// Initial check for any checked input and set up event listeners
ratingItems.forEach(function(ratingItem, index) {
var input = ratingItem.querySelector("input[type='radio']");
// If input is checked on load, apply selected classes
if (input.checked) {
applySelectedClasses(index);
}
// Add event listeners for change, hover, and focus
input.addEventListener("change", function() {
applySelectedClasses(index);
});
ratingItem.addEventListener("mouseenter", function() {
applyActiveClasses(index);
});
ratingItem.addEventListener("focusin", function() {
applyActiveClasses(index);
});
ratingItem.addEventListener("mouseleave", conditionalRemoveActiveClasses);
ratingItem.addEventListener("focusout", conditionalRemoveActiveClasses);
});
// Function to add "selected" and "active" class up to the selected item
function applySelectedClasses(currentIndex) {
// First, clear all classes to reset the selection
ratingItems.forEach(function(ratingItem, index) {
ratingItem.classList.remove("active", "selected");
if (index <= currentIndex) {
ratingItem.classList.add("active", "selected");
}
});
}
// Function to temporarily add "active" class up to the current item on hover/focus
function applyActiveClasses(currentIndex) {
ratingItems.forEach(function(ratingItem, index) {
// Apply "active" only if index is up to the current index
// Preserve "selected" items even when applying "active"
ratingItem.classList.toggle("active", index <= currentIndex || ratingItem.classList.contains("selected"));
});
}
// Function to remove "active" classes added by hover/focus if not "selected"
function conditionalRemoveActiveClasses() {
ratingItems.forEach(function(ratingItem) {
if (!ratingItem.classList.contains("selected")) {
ratingItem.classList.remove("active");
}
});
}
})();Report Issues
Find a bug? Want a new feature? Report it on JIRA. You're so awesome!