Modern CSS Star Rating Component
See the Pen Modern CSS Star Rating Component.
Tech & Dependencies
Features
- ✓ CSS :has() Logic
- ✓ Clip-path Shapes
- ✓ JS-free Interaction
- ✓ Keyboard Accessible
Browser Support
Core
This Modern CSS Star Rating Component represents a major shift in UI development, moving complex logic from JavaScript to pure CSS. It utilizes the powerful :has() selector to track sibling states, allowing the UI to highlight stars both before and after the interaction point. The stars themselves are created using clip-path instead of bulky SVG icons, resulting in a lightweight, scalable, and highly performant rating system.
Core Technique
The “secret sauce” of this component is how it handles backward selection. Traditionally, CSS could only select “forward” (using the ~ combinator). By using .star:has(~ .star:hover), we can now style a star if any of its succeeding siblings are being hovered. This allows the component to fill the entire range from the first star to the current cursor position or the selected value.
Visually, the stars are constructed using two pseudo-elements (::before for the border/outline and ::after for the fill). Both use a complex polygon() clip-path to define the five-pointed shape. When a radio button is checked, the component uses :has(:checked) to scale up the selected star and update the --star-bg variable across the relevant range, providing a fluid, reactive feel.
Customization
The component is built with maintainability in mind, using CSS variables for key visual properties. You can easily adjust the theme, sizing, and animation speeds.
.star-rating {
/* Change the primary highlight color */
--star-rating-bg: gold;
/* Adjust font size to scale the entire component */
font-size: 1.75rem;
}
.star::after {
/* Fine-tune the transition speed */
transition: all ease-in-out 333ms;
}
/* Modify star shape */
.star::before, .star::after {
/* Change polygon points for different shapes */
clip-path: polygon(50% 0%, ...);
}
Tips
1. Accessibility (A11y):
Unlike many “hacked” CSS rating systems, this one uses native <input type="radio">. This means it works perfectly with keyboard navigation (Tab and Arrow keys) out of the box. To ensure users can see where they are, we use :focus-visible:
input[type="radio"]:focus-visible + label {
outline: 2px solid gold; /* Clear keyboard focus indicator */
}


