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