Star Rating Animated
A real 1 to 5 star rating: click, touch or arrow keys, the stars light up to the choice with a small bounce, and the rating is sent with the form.
Updated
This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Data has 28 effects, including 1 free. Explore the category →
3 usage examples



How it works
Each star is a real radio button: <label class="strt-star"> holds an <input type="radio" name="note" value="1…5"> made invisible but laid over the star, the ★ character (.strt-glyph) and a text for screen readers ("4 stars out of 5"). The set is a <fieldset> named by its <legend> "Your rating". Click, touch, Tab then arrows: everything a browser radio group does works here without script, including sending note=4 with the surrounding form.
The script lights the stars up to the checked rating (class is-on: yellow #fbbf24, 20% larger) and makes them bounce (@keyframes strt-pop, 0.3 s) on every new choice, and once when the starting rating appears on screen. On hover, the CSS previews up to the pointed star without checking anything. A form reset brings the stars back to the HTML rating.
Several ratings in one page: if two groups share the same name (same form, or both outside any form), the script renames the second (note-2, note-3…) and gives each one back the rating checked in its HTML. Nothing is declared on window. To read the rating: the change event bubbles up to the root, and root.querySelector('.strt-input:checked').value gives the value.
Accessibility
- Native radio group: screen readers announce "Your rating, group", then "4 stars out of 5, radio button, checked, 4 of 5". The drawn stars are hidden (
aria-hidden). - Keyboard: Tab enters the group on the checked star, arrows change the rating, Tab leaves. Focus is visible: a 2 px outline around the star (
:focus-visible, colour--strt-focus). - Touch: the whole star area takes the finger, since the radio button covers it entirely.
- Reduced motion: under
prefers-reduced-motion: reduce, no bounce and no transition; the stars light up directly. - Limit: no half stars; a rating to the nearest 0.5 would need ten radio buttons.
Browser compatibility
Native radio buttons, CSS and dependency-free JavaScript (about 3 KB). Measured on 08/11/2026 in Chromium 151, Firefox 153 and WebKit 26.5 (Playwright): click and touch on the 2nd copy without touching the 1st, Tab then left arrow (4 → 3), focus outline, value sent by a form (note=4), names of the four copies note, note-2, note-3, note-4, 390 px, reduced motion, no error. Versions taken from @mdn/browser-compat-data: :focus-visible sets the minimum for the outline.
Older (from Chrome 51, Firefox 55, Safari 12.1): everything works except the focus outline. Without JavaScript, the rating stays a usable radio group sent with the form, but the stars only light up on hover.
The code
HTML structure to paste into your page (the CSS + JS come with your purchase):
<div class="fx-0239-root">
<fieldset class="strt-rating">
<legend class="strt-legend">Your rating</legend>
<div class="strt-stars">
<label class="strt-star">
<input class="strt-input" type="radio" name="note" value="1">
<span class="strt-glyph" aria-hidden="true">★</span>
<span class="strt-sr">1 star out of 5</span>
</label>
… (4 more labels, value 2 to 5; checked on the starting rating)
</div>
</fieldset>
</div>
One-time payment, no subscription — the code is yours forever
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
Starting rating (HTML — checked on a .strt-input) |
4 | Remove checked everywhere for a blank rating, or move it to another star. |
Sent name (HTML — name of the radio buttons) |
note | Field name in the form. Keep the same name on the five buttons of one rating. |
Legend and read texts (HTML — .strt-legend and .strt-sr) |
"Your rating" · "1 star out of 5"… | What a screen reader hears. The legend is hidden by default: remove .strt-legend from the hiding rule to show it. |
Colours (CSS — --strt-on, --strt-off, --strt-focus) |
#fbbf24 · white at 20% · #6366f1 | Lit stars, unlit stars, focus outline. On a light background, an unlit colour such as #e5e7eb. |
Size (CSS — --strt-size) |
2rem | Size of the ★ character; 1rem in a list, 3 to 4rem on a kiosk. |
| Number of stars (HTML) | 5 | Add a label with value="6" for a rating out of 6, and adapt the "out of 5" texts. |
Background and height (CSS — --strt-bg, --strt-height) |
#0a0a0f · 300px | Inside a form: --strt-bg:transparent; --strt-height:0px. |
FAQ
change on the root: root.addEventListener('change', () => console.log(root.querySelector('.strt-input:checked').value)). Inside a form, the rating is sent with the other fields on its own.disabled on the <fieldset> (no more click or keyboard) and .strt-stars{pointer-events:none} to stop the hover preview; screen readers will announce disabled buttons.name in one form (or both outside any form) are a single group to the browser: checking one would uncheck the other. So the script renames the second rating (note-2). Give different names in your HTML to keep control of the names sent.