Utilities✨ Premium

Rating Stars

1 to 5 star rating chosen with the mouse, a finger or the arrow keys: a real radio group, golden fill on hover, a cascade when the rating is set.

JSInteractiveRating

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Utilities has 43 effects, including 3 free. Explore the category →

3 usage examples

Rating the courier at the end of a food order — Rating Stars example 1

① Rating the courier at the end of a food order

WhenThe meal has just arrived: the app's bottom sheet asks "How did Karim's delivery go?". The customer taps the fourth star, changes their mind for the fifth, then sends.
WhyThe rating takes one gesture, no keyboard; the word "Very good" confirms what is about to be sent, and the golden cascade makes the choice clear on a phone screen.
Settings--rts-size: 2.4rem, --rts-gap: 10px, --rts-fill: #d97706, --rts-empty: #85859b, --rts-text-color: #4b5563 for the white background; demo frame set to zero. In the capture, the scene clicks stars 4, 5, 3, 4 every 1.1 s (click on the real <label>).
Small stars in an online course outline — Rating Stars example 2

② Small stars in an online course outline

WhenIn a ceramics course outline, each finished lesson carries its row of stars; the student hovers over the current lesson, rates it 4, then rates the next one.
WhyFour independent groups on the same page, two already rated in the HTML: the rating is given where the course is followed, with no separate screen.
SettingsFour roots, name lecon1 to lecon4, ratings 4 and 5 checked in the HTML; --rts-size: 1.05rem, --rts-gap: 3px, --rts-fill: #d97706, --rts-empty: #8f877f, --rts-text-size: .72rem, text placed on the right by the scene's CSS. The capture mouse hovers over the stars; the scene rates lessons 3 and 4 every 1.2 s.
Satisfaction kiosk at a museum exit — Rating Stars example 3

③ Satisfaction kiosk at a museum exit

WhenLeaving the exhibition, the visitor taps one of the kiosk's five large stars; the rating shows in words and the kiosk thanks them.
WhyAt this size, the stars are easy to hit, even in passing. The kiosk reacts to the real radio group's change event to show its thank-you.
Settings--rts-size: 4.4rem, --rts-gap: 14px, --rts-text-size: 1.15rem, --rts-text-color: #e6e9f0, starting text "Tap to rate". The thank-you is a scene element shown on change; stars clicked every 1.3 s in the capture.

How it works

Each star is a <label> holding a hidden radio button; the five are grouped in a <fieldset>. Picking a star means checking its button: by click, by touch, or with the keyboard using Tab then the arrows. Inside a <form>, the rating is sent with the form under the name note (value 1 to 5), and the form's reset button clears the stars too.

Each star is a grey ★ covered by a golden copy (#fbbf24), cut by clip-path: inset(). On mouse hover, the stars fill up to the one being pointed at; when leaving, they go back to the chosen rating. When a rating is chosen, the filled stars grow one after the other (rtsPop, 0.3 s, 50 ms apart) and the text becomes the word from data-rts-word followed by the rating: "Very good (4/5)".

Empty stars are #70708c, 3.6:1 on the #1a1a2e background. A rating already checked in the HTML shows on load. Each .fx-0741-root is its own group: outside a form, if two groups share the same name, the script renames one so they do not mix. Listen to the native change event on the root to send the rating.

Accessibility

  • Real radio group: the screen reader announces "Your rating, group" then "3 stars out of 5, radio button, 3 of 5". The legend and names are visually hidden text, to translate in the HTML.
  • Keyboard: Tab enters the group, the arrows change the rating, Tab leaves; lavender ring around the focused star. In Safari on Mac, Tab only enters the group with the system keyboard option (otherwise Option + Tab).
  • Rating announced: the "Very good (4/5)" text is in an aria-live="polite" area, read after each choice.
  • Contrast: empty star at 3.6:1 on the default background, full star at 10:1. On a white background, use a deeper gold (--rts-fill: #d97706) and a darker grey: the #fbbf24 gold is only 1.7:1 on white.
  • Reduced motion: no cascade and no growth on hover; the stars fill in place.

Browser compatibility

Native HTML form, CSS and 2.9 KB of commented, dependency-free JavaScript. Measured in Chromium 151, Firefox 153 and WebKit 26.5 (Playwright): code pasted twice (each group keeps its rating), click, touch at 390 px, arrow keys, reduced motion, form submitted then reset, 0 errors, no name added to window.

Chrome 87+✓ Full (measured)
Firefox 85+✓ Full (measured)
Safari 15.4+✓ Full (measured in WebKit)
Edge 87+✓ Full (Chromium engine)
Mobile iOS 15.4+✓ WebKit engine, not checked on a device
Android Chrome 87+✓ Full (touch measured)

Without JavaScript, the radio buttons work and the rating is sent with the form, but the stars do not colour. The inset property that lays the button over the star dates from Chrome 87, Firefox 66 and Safari 14.1; the :focus-visible focus ring from Chrome 86, Firefox 85, Safari 15.4. Hover uses Pointer Events (Chrome 55, Firefox 59, Safari 13).

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0741-root">
  <div class="rts-demo">
    <fieldset class="rts-stars">
      <legend class="rts-vh">Your rating</legend>
    <label class="rts-star"><input type="radio" name="note" value="1" data-rts-word="Bad"><span class="rts-glyph" aria-hidden="true">★</span><span class="rts-vh">1 star out of 5</span></label>
    <label class="rts-star"><input type="radio" name="note" value="2" data-rts-word="Fair"><span class="rts-glyph" aria-hidden="true">★</span><span class="rts-vh">2 stars out of 5</span></label>
    <label class="rts-star"><input type="radio" name="note" value="3" data-rts-word="Good"><span class="rts-glyph" aria-hidden="true">★</span><span class="rts-vh">3 stars out of 5</span></label>
    <label class="rts-star"><input type="radio" name="note" value="4" data-rts-word="Very good"><span class="rts-glyph" aria-hidden="true">★</span><span class="rts-vh">4 stars out of 5</span></label>
    <label class="rts-star"><input type="radio" name="note" value="5" data-rts-word="Excellent"><span class="rts-glyph" aria-hidden="true">★</span><span class="rts-vh">5 stars out of 5</span></label>
    </fieldset>
    <span class="rts-text" aria-live="polite">Click to rate</span>
  </div>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Rating words (HTML — data-rts-word on each radio button) Bad · Fair · Good · Very good · Excellent Word shown and announced before "(n/5)".
Group name (HTML — the radio buttons' name) note Name sent with the form; give each group on a page a different name.
Starting rating (HTML — checked on a radio button) none Shows a rating already given, read back from your database for instance.
Size and gap (CSS — --rts-size, --rts-gap) 2.5rem · 8 px Giant stars for a kiosk, small ones for a list.
Colours (CSS — --rts-fill, --rts-empty) #fbbf24 · #70708c Keep at least 3:1 between the empty star and your background.
Text (CSS — --rts-text-color, --rts-text-size, --rts-text-gap) white at 60 % · .9rem · 15 px Darken it on a light background.
Frame (CSS — --rts-height, --rts-page, --rts-panel, --rts-pad) 300 px · #0a0a0f · #1a1a2e · 20 px 0 and transparent to fit it into your card.

FAQ

In a form, it is sent on its own (note=4). In JavaScript: root.addEventListener('change', e => send(e.target.value)), or read root.querySelector('input:checked').value.
Not by clicking again: a radio group always keeps a choice once checked. To start over, put the stars in a form with a type="reset" button: stars and text go back to the start.
Not with this code: each star is a whole choice from 1 to 5. To show an average (4.3/5) read-only, another component fits better than a radio group.