Data✨ Premium

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.

CSSInteractive

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

Rating a recipe just cooked — review block at the bottom of the recipe — Star Rating Animated example 1

① Rating a recipe just cooked — review block at the bottom of the recipe

WhenAfter the last step of a leek tart, the cook picks stars under "Did you cook it?"; the chosen rating is written next to the "Post my review" button, with an optional comment.
WhyA rating is the quickest answer to give: one click is enough, the bounce confirms it was taken, and the value is sent with the rest of the review form.
SettingsInside a <form>, name="note-recette", no star checked at start, --strt-size:2.1rem, --strt-on:#f59e0b, --strt-off:#ead7c4, --strt-focus:#c2410c, transparent background, left-aligned. The "Your rating: …" text is written by the scene on the change event. In the capture, the first click (which lands below the stars) is replayed on the label of the 5th star; the second lands right on that star.
One rating per bottle — list in a virtual wine cellar — Star Rating Animated example 2

② One rating per bottle — list in a virtual wine cellar

WhenIn "My cellar", each bottle has its own row of small pink stars; the enthusiast rates the wine just opened and revises another one, by click or keyboard, without leaving the list.
WhyIn a personal list, the rating is a memory aid: each row has its own rating, set in place, and a glance is enough to find the best bottles again.
SettingsFive roots, one per row, different name values (cave-1 to cave-5), a legend per bottle ("Your rating for Vendrasque estate"), --strt-size:1.15rem, --strt-on:#f9a8d4, --strt-off:#4a3340. In the capture, the first click (outside the stars) is replayed on star 4 of the 4th bottle; the second really lands on the 1st star of the 3rd bottle, which drops to 1, and the moving mouse shows the hover preview.
Satisfaction kiosk at a media library exit — giant stars to touch — Star Rating Animated example 3

③ Satisfaction kiosk at a media library exit — giant stars to touch

WhenOn the screen by the exit, the visitor touches one of five large stars under "Did you enjoy your visit?"; a thank-you shows the rating, then the kiosk resets four seconds later for the next person.
WhyA kiosk must be understood without instructions and touched without aiming: 60 px stars fill the screen and the bounce confirms the gesture from arm's length.
Settings--strt-size:3.7rem, 8 px margin per star, --strt-on:#fde047, --strt-off:rgba(236,254,255,.18), transparent background on a teal gradient; the hover preview is turned off by the scene CSS, useless on a touch screen. The rating sits in a <form>: the scene calls form.reset() after 4 s and the effect turns the stars back off.

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.

Chrome 86+✓ Full (measured)
Firefox 85+✓ Full (measured)
Safari 15.4+✓ Full (measured in WebKit)
Edge 86+✓ Full (Chromium engine)
iOS Safari 15.4+✓ Not checked on a real device
Android Chrome 86+✓ Full (Chromium engine)

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):

index.html — structure
<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 / propertyDefaultEffect
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

Listen to 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.
That is not what this effect is for: it is a field to fill in. If you use it anyway, add 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.
Two radio groups with the same 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.