More Forms Snippets
Star Rating — Free HTML CSS JS Snippet
Star Rating · Forms · Plain HTML, CSS & JS · Live preview
What's included
Features
About this UI Snippet
Star Rating — Hover Preview, Click-to-Set & Label Feedback

A star rating component collects user satisfaction input — product reviews, service ratings (aggregated in a rating breakdown), survey responses. The interaction pattern is well-established: stars highlight as you hover to preview the rating, click to lock it in, and the selection persists when you move the mouse away. This snippet implements the full pattern with hover preview, click-to-set, mouseleave restore, and descriptive text labels.
How the hover preview works
Each star is a span with a data-v attribute (1–5). The mouseenter handler uses classList.toggle('active', +x.dataset.v <= v) to compare each star's value to the hovered value and adds .active (amber) to all stars at or below the cursor.
Storing the selected rating
A selected variable stores the clicked value. On mouseleave from the container, the stars reset to show the selected value. If selected is 0, all stars go grey.
The label feedback
The labels array maps indices to descriptive words: Poor, Fair, Good, Great, Excellent at positions 1–5. The .hint element shows the current hover label during hover and the selected label plus thanks after click.
Reading the value
After the user clicks, selected holds the value 1–5. Add a hidden input and update its value: document.getElementById('rating').value = selected. Submit the hidden input with your form data.
Hover preview with CSS sibling selectors
The star rating uses the CSS general sibling combinator (~) in reverse order trick. The input elements are hidden radio buttons ordered 5 to 1. When a star is hovered, CSS .star:hover ~ .star selects all subsequent siblings and removes their colour, while the hovered star and all stars before it get the accent colour. This creates the hover preview effect without any JavaScript — just CSS sibling relationships.
Click-to-set with radio inputs
Each star is a label associated with a hidden radio input. Clicking a label checks its radio input. The :checked pseudo-class then applies the filled colour to that star and all preceding stars via the same sibling combinator logic. The rating is accessible via standard form input — a form POST includes the rating value automatically.
The half-star pattern
For half-star ratings (3.5, 4.5), use two overlapping label elements per star: one for the left half and one for the right. Each half has its own radio input value (3.0, 3.5, 4.0, 4.5, etc.). The clip-path: inset(0 50% 0 0) clips each half-star to its respective side.
Build with AI
Build, Understand, Optimize, and Extend It With AI
You don't need to work out the hover-versus-selected state handoff by hand. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why the mouseleave handler re-derives the active stars from the selected variable instead of just removing every active class, or how classList.toggle with a comparison against data-v produces the "fill up to here" effect from a single shared loop. The same assistant can help optimize it, for example checking whether attaching a separate mouseenter listener per star (rather than one delegated listener on the container) matters at this scale. It's also useful for extending the feature: ask it to add keyboard support so arrow keys and Enter can set a rating without a mouse, support half-star precision, or persist the selected rating to a hidden form field automatically instead of requiring a manual wiring step. Treat the code less like a finished artifact and more like a starting point for a conversation.
Prompt to recreate it
Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:
Build an interactive star rating control in plain HTML, CSS, and JavaScript, no framework, no libraries.
Requirements:
- Five star characters, each carrying a numeric value in a data attribute (1 through 5), plus a text hint element below them.
- On mouseenter of any star, read that star's value and loop through all five stars, adding a highlight class to every star whose value is less than or equal to the hovered value and removing it from the rest — using a single comparison-based toggle call per star, not separate add/remove branches.
- Update the hint text during hover to show a descriptive word (for example Poor, Fair, Good, Great, Excellent) corresponding to the hovered value, sourced from an array indexed by the star value.
- Clicking a star must store its value in a variable representing the confirmed selected rating, and update the hint to a confirmation message that includes the descriptive word for that rating.
- On mouseleave of the entire star container (not each individual star), restore the highlighted stars to reflect the confirmed selected rating rather than the hover state, and restore the hint text to either the confirmation message (if a rating was previously selected) or a prompt to click and rate (if nothing has been selected yet).
- Unselected/unhovered stars must render in a light neutral gray, not be hidden or removed, so the full five-star scale is always visible regardless of the current rating.
- As a documented extension in a code comment, describe how to read the confirmed rating into a hidden form input's value so it submits along with the rest of a form.Step by step
How to Use
- 1Hover and click in the previewHover over the stars to see the highlight preview. Click a star to lock the rating. Move the mouse away to confirm the selection persists.
- 2Update the label textIn the JS panel, update the labels array. The hint text uses these labels on hover and after selection.
- 3Change the star sizeIn the CSS panel, update font-size: 36px on .stars span to resize all stars.
- 4Change the active star colourUpdate color: #f59e0b on .stars span.active to any amber, yellow, or brand colour.
- 5Submit the valueAfter click, the selected variable holds 1–5. Add document.getElementById(your-input).value = selected in the click handler to populate a hidden form input.
- 6Export in your formatClick HTML for a standalone file, JSX for a React component, or Tailwind for a React + Tailwind version.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
Each star span has a data-v attribute (1–5). The mouseenter handler captures the hovered value v, then loops through all stars with classList.toggle(active, +x.dataset.v <= v). Stars with a value at or below the hovered star get the .active class.
A selected variable (initialised to 0) stores the clicked value. On mouseleave, the stars reset to show the selected value. If selected is 0, all stars are grey.
Add a hidden input to your form. In the click handler, set document.getElementById(rating-input).value = selected. The form will submit the rating value.
Remove event listeners. Pre-compute the number of full stars and add .active to that many spans. For a fractional average, use clip-path on the last star.
Yes. Add or remove span elements and update the labels array length. The toggle logic uses data-v attributes so it works with any count.
Yes. Click JSX to download a React component. Replace selected with useState and highlight stars up to the hovered or selected index in render.