Overview
Star rating control built on real <input type="radio"> in reverse order so the sibling combinator (.star-rating input:checked ~ label) can paint fills onto stars to the right of (visually before) the checked input. Hover previews work via the same combinator with :hover in place of :checked.
When to use it
Reach for star ratings on review surfaces, feedback forms, any place a 1-5 (or 1-10) selection needs to feel tactile. Skip stars for content where rating granularity matters beyond the visible step count (use a slider). Skip them when the rating is one-shot and read-only — static SVG icons read clearer.
How it works
Render five radio inputs in DOM order 5, 4, 3, 2, 1 (reversed) with flex-direction: row-reverse so they display left-to-right but the markup is right-to-left. This gives the sibling combinator the geometry it needs: input:checked ~ label selects all labels after the checked input in DOM order, which visually means all stars to the left of the selected star — exactly what should be filled. Hover preview uses the same selector with :hover: .stars:hover input ~ label { fill: none } clears all fills, then label:hover, label:hover ~ label { fill: gold } paints the hovered star and everything visually before it.
Production gotchas
Reverse-order DOM hurts keyboard navigation because tab order follows DOM order — arrow keys jump in reverse-visual order. Wrap the radio group with a directional aria-label describing the scale (“Rate from 1 to 5 stars”) and accept that this trade-off favors visual elegance over keyboard ergonomics; for accessibility-critical surfaces use real<button>s with JS state instead. The sibling combinator only walks forward, so it cannot fill stars on the wrong visual side — if the reversed layout is breaking flex-direction, double-check the parent does not override row-reverse.
Accessibility
The native radio inputs carry the accessible name from their <label> children — screen readers announce “5 stars” etc. correctly. Keep the aria-label on the wrapping <fieldset> describing what is being rated. Under prefers-reduced-motion: reduce drop the fill transition so stars snap to filled state without the sliding paint. Verify keyboard arrow key behavior reads in visual left-to-right order despite the reversed DOM.
References
Implementation depth
The hover preview should not replace the committed rating. Radio inputs keep the saved value clear, while sibling selectors can preview future fills as the pointer or keyboard moves through options.
Keyboard behavior is the test that matters. Arrow keys should move through values predictably, the selected value should be announced, and reduced motion should keep the star fill state immediate.