Skip to content
WingoUI
ComponentsTemplatesDocsPricingAI agentsBlogChangelog
  1. Home
  2. Blog
  3. Component guides
  4. React Rating Stars: Half Values, Hover and Keyboard
Auf Deutsch lesen
  1. Blog
  2. Component guides
  3. React Rating Stars: Half Values, Hover and Keyboard
Component guides
Component guides

React Rating Stars: Half Values, Hover and Keyboard

SR
Serban Rusu · Founder of Wingo UI
Oct 19, 2026 · 9 min read

On this page

0%
  1. What should a React rating component handle?
  2. How do the React star rating packages compare?
  3. How do I add a React star rating to a form?
  4. How do half star ratings work in React?
  5. What do keyboard and screen reader users get?
  6. How does the rating work on a phone?
  7. How do I show review stars and the summary they feed?
    1. How do review stars show up in Google?
  8. What are the common star rating pitfalls?
  9. How do I add it to my project?
  10. FAQ
    1. How do I make a half star rating in React?
    2. Should a star rating be a radio group or a slider?
    3. How do I show an average like 4.3 stars?
    4. Can Google show my review stars in search results?
    5. Is the Wingo UI Rating free?

TL;DR

Good React rating stars need four things beyond a row of icons: half values picked by the pointer position, a hover preview that shows what a click will do, full keyboard control with a spoken value, and a touch scrub with 44px targets. The Wingo UI Rating covers these with allowHalf, labels and a controlled value, and the Reviews component turns the saved ratings into an average, a 5 to 1 breakdown and a filterable list.

Published Oct 19, 2026

You need React rating stars for a product review, a seller rating or a feedback form. Five star icons and a click handler take ten minutes. Then someone asks for half stars, a keyboard user tabs to the row and nothing moves, a phone user drags a thumb across the stars and the page scrolls instead, and the product page still has to turn 126 ratings into an average and a breakdown. This guide covers what a React star rating component has to handle, how the common packages compare, and full examples with the Wingo UI Rating and Reviews.

What should a React rating component handle?

Six things. Five icons with a click handler cover only the first:

  1. Click or tap to rate, with a way to clear the rating again.
  2. Half values chosen by where the pointer lands on the star.
  3. A hover preview, so the stars and the label show what a click will pick before it happens.
  4. Keyboard control with a value a screen reader can speak ("Good", "3.5 of 5").
  5. A touch layout: targets of at least 44px and a finger scrub that does not scroll the page.
  6. A read-only mode for averages like 4.3, drawn as a fraction of a star.

The last one connects the input to the output. The stars people pick in a form are the same stars a product page shows next to the average, so one component should do both.

How do the React star rating packages compare?

MUI Rating is the most complete if you already use Material UI, the small npm packages are fine for a quick display, and the Wingo UI Rating is a Pro source component built for touch and forms. Facts below come from each project's docs, README and the npm registry, checked October 2026.

OptionWhat it isHalf valuesKeyboard and screen readersLast published
MUI Rating (opens in a new tab)Part of @mui/material (MIT)precision={0.5}Visually hidden radio inputs, one per star plus 0; arrow keys change the value@mui/material 9.5.0, October 2026
@smastrom/react-rating (opens in a new tab)Zero-dependency package (MIT)Read-only floats, drawn to the nearest halfARIA radio group; arrows move, Enter or Space confirms1.5.0, January 2024
react-rating-stars-component (opens in a new tab)Fork of react-stars (ISC)isHalf, on by defaulta11y prop, on by default: arrow keys and number keys2.2.0, July 2020
Wingo UI RatingPro source component, npx wingo-ui@latest add ratingallowHalf, by pointer position and 0.5 key stepsOne slider with aria-valuetext, arrows, Page keys, Home, End and digits; touch scrub with 44px targetsPart of the library

If your app is on Material UI, use MUI Rating: it is well documented and its hover label example (onChangeActive) covers the preview. If you only display a score, a small package or a read-only component is enough, though react-rating-stars-component has not been published since 2020. The rest of this guide is about the Wingo UI Rating.

How do I add a React star rating to a form?

Give it a label, a controlled value and a name. With name, a hidden input submits the value, so a plain form or a Server Action reads it like any other field: "0" when empty, "4.5" with halves.

bash
npx wingo-ui@latest add rating textarea button
tsx
"use client";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Rating } from "@/components/ui/rating";
import { Textarea } from "@/components/ui/textarea";
const LABELS = ["Very poor", "Poor", "Okay", "Good", "Excellent"];
export function ReviewForm({ saveReview }: { saveReview: (data: FormData) => Promise<void> }) {
const [rating, setRating] = useState(0);
const [tried, setTried] = useState(false);
return (
<form
noValidate
className="flex flex-col gap-4"
action={async (data) => {
// the hidden input sends "0" while nothing is chosen
if (Number(data.get("rating")) === 0) {
setTried(true);
return;
}
await saveReview(data);
}}
>
<Rating
label="How was your experience?"
name="rating"
value={rating}
onValueChange={(next) => {
setRating(next);
if (next > 0) setTried(false);
}}
labels={LABELS}
showLabel
emptyLabel="Tap a star"
required
error={tried && rating === 0 ? "Choose a rating." : undefined}
/>
<Textarea label="Comment" name="comment" maxLength={500} showCount minRows={2} />
<Button type="submit">Send review</Button>
</form>
);
}

labels does two jobs: with showLabel the hovered or chosen label shows beside the stars, and each label is what a screen reader hears for that value. required only draws the mark after the label, so the check stays in your form, as above. error tints the empty stars red and sets aria-invalid. The label, description and error come from the free Field anatomy, the same one every Wingo UI input uses.

Hover over the stars, then click one. Try Send rating without choosing anything first.

Hover the stars to preview a rating and its label, click to pick one, then press Send rating. Sending with no rating shows the error
$ npx wingo-ui@latest add rating
ProRating docs

How do half star ratings work in React?

Each star is split at its midpoint. With allowHalf, a pointer on the left half of a star gives x.5 and the right half gives the whole star (mirrored on right-to-left pages). The fill is the same icon drawn twice: an empty layer at low opacity and a colored layer clipped to a percentage, so a half star is a 50% clip of the full icon. That is why any lucide icon works through the icon prop, such as <Heart />. Another half star rating React pattern is a separate half glyph (react-rating-stars-component takes a halfIcon prop); the clip makes that unnecessary.

tsx
<Rating aria-label="Rate this bike" allowHalf tone="warning" showValue locale="en-US" defaultValue={3.5} />

tone="warning" gives the classic amber stars; the default neutral is black in light mode and white in dark mode, and color takes any CSS color. showValue prints the number through Intl ("3.5" in en-US, "3,5" in de-DE) and reserves the width of the widest number, so the stars never shift while the value changes.

The hover preview follows the pointer. The part of the preview beyond the chosen value is dimmed, so you can see both the current rating and the one a click would set. After a click, the preview waits until the mouse reaches another value, so the result is not hidden under a still cursor.

allowHalf with amber stars: move the pointer across one star to see the half and the whole value, then use the arrow keys to step by 0.5
$ npx wingo-ui@latest add rating
ProRating docs

What do keyboard and screen reader users get?

The row is one Tab stop with role="slider", aria-valuemin, aria-valuemax, aria-valuenow and aria-valuetext. The keys:

  • Right or Up adds one step (0.5 with allowHalf), Left or Down removes one. Right and Left swap on right-to-left pages.
  • PageUp and PageDown move a whole star.
  • Home clears, or goes to the lowest value when clearable={false}. End jumps to the top.
  • Digits 1 to 9 pick a value directly. 0, Backspace and Delete clear.

Radio groups are the other common pattern, and they are a fine choice: MUI uses hidden native radios, and @smastrom/react-rating an ARIA radio group. We picked one slider because the half steps, the Page keys and the digit shortcuts map onto a single value, and because aria-valuetext lets each value speak a word. Without labels, getValueText decides what is read (by default "3.5 of 5"); with them, whole values read the label ("Good"). Pass your own function to translate it.

A read-only rating is display only. It gets role="img" and a name from getReadOnlyLabel ("Rated 4.8 of 5"), leaves the tab order and draws fractions like 4.3 proportionally.

How does the rating work on a phone?

A finger has no hover, so touch gets a scrub instead. Press on the stars, drag across them and lift to commit; the stars follow the finger, and touch-action: none on the row keeps the page from scrolling during the drag. Sliding past the first star clears the rating when clearable is on (the default).

On a coarse pointer every star becomes a 44px target, and the row spreads its icons to that pitch. If ten stars would overflow a narrow screen, the row shrinks the spacing between them so it still fits, and the number stays on the same line. The reasoning behind the 44px number is in our post on minimum touch target size in React and Tailwind. On release, the filled stars pop on a small staggered spring; with reduced motion turned on in the system settings they fill without the animation.

How do I show review stars and the summary they feed?

Collect ratings with the Rating, show them with the Reviews component. React review stars on a product page are the same Rating in read-only mode, placed inside a summary and a list. Reviews takes the list of reviews and a summary with the average, the count and the distribution as counts for 5, 4, 3, 2 and 1 stars. It renders the average with read-only half stars, five bars that filter the list on tap, a sort menu (a bottom sheet on phones), photos that open full screen, and Helpful votes that roll back if saving fails.

tsx
import { Reviews, type ReviewData } from "@/components/ui/reviews";
export function ProductReviews({ reviews }: { reviews: ReviewData[] }) {
return (
<Reviews
reviews={reviews}
summary={{ average: 4.6, count: 126, distribution: [92, 21, 7, 3, 3] }}
tone="warning"
locale="en-US"
onHelpfulChange={async (id, helpful) => {
const res = await fetch(`/api/reviews/${id}/helpful`, { method: helpful ? "POST" : "DELETE" });
if (!res.ok) throw new Error("Vote failed");
}}
/>
);
}

Pass summary from the server when the list is paged. Without it, Reviews calls summarizeRatings(reviews), which only sees the loaded page: ratings round to the nearest star for the bars and the average keeps two decimals. The ReviewsSummary part renders the summary on its own, for a seller card or a product header.

Tap the 4 star bar, then tap it again. Open the sort menu and a review photo.

Tap a bar in the breakdown to show only those reviews and tap it again to see all. Sort the list, open a photo full screen and mark a review as helpful
$ npx wingo-ui@latest add reviews
ProReviews docs

How do review stars show up in Google?

Through AggregateRating structured data in the page; the component itself adds none. Google's review snippet documentation (opens in a new tab) requires ratingValue and at least one of ratingCount or reviewCount, assumes a best rating of 5 and a worst of 1 when you omit them, and excludes pages where a LocalBusiness or Organization controls the reviews about itself (checked October 2026). The same numbers you pass to summary fill it:

tsx
const jsonLd = {
"@context": "https://schema.org",
"@type": "Product",
name: "City bike",
aggregateRating: { "@type": "AggregateRating", ratingValue: 4.6, reviewCount: 126 },
};

Rendering it safely in the App Router is covered in the Next.js JSON-LD guide.

What are the common star rating pitfalls?

Five, and each one is fixed by a prop or by sending the right numbers from the server:

  • No accessible name. A rating without label needs an aria-label, or a screen reader announces an unnamed slider.
  • Halves with per-value icons. icons (one face per value, like Frown, Meh, Smile, Laugh) lights up one icon at a time and ignores allowHalf. Use icon for halves.
  • Rounding the average. A 4.4 drawn as four stars hides real information. Use a read-only rating, which draws the fraction.
  • Saving on every hover. onValueChange fires on commit only: on the release of a tap or scrub and on each key press. Save there, never in a pointer handler.
  • Summaries from one page. summarizeRatings on the first page of reviews is not the product's average. Send the totals from the server.

How do I add it to my project?

Run npx wingo-ui@latest add rating (or reviews). The CLI copies the source into components/ui, adds the hooks and helpers it imports, and installs motion and lucide-react. Rating and Reviews are Pro components (pricing); the Textarea, Field and Button used in the form above are free. For the rest of the form, the React form components guide applies the same keyboard, touch and error rules to every input, and the component guides category has more single-component deep dives.

Components in this post

  • Rating

    A React star rating to rate or show a score with stars or any icon: half values, a hover preview, a label per value and a fill that pops.

    Pro
  • Reviews

    A React reviews section for products and sellers: average, stars, a 5 to 1 filter breakdown, and sortable reviews with photos and replies.

    Pro

FAQ

How do I make a half star rating in React?

Split each star at its midpoint: a click on the left half gives x.5, the right half a whole star, and the fill is the same icon clipped to a percentage. In the Wingo UI Rating that is the allowHalf prop, which also makes the arrow keys move by 0.5.

Should a star rating be a radio group or a slider?

Both are used. MUI Rating and @smastrom/react-rating build a radio group, while the Wingo UI Rating is one slider with aria-valuetext, so a screen reader hears "Good" or "3.5 of 5" instead of a bare number. Whichever you pick, give every value a text label and keep the current value announced.

How do I show an average like 4.3 stars?

Render the rating read-only and let it draw the fraction. A read-only Wingo UI Rating paints 4.3 proportionally, keeps one decimal in the number and is announced as "Rated 4.3 of 5".

Can Google show my review stars in search results?

It can, if the page has valid AggregateRating or Review structured data with ratingValue and a ratingCount or reviewCount. Pages where a LocalBusiness or Organization reviews itself are not eligible for the star feature.

Is the Wingo UI Rating free?

No. Rating and Reviews are Pro components. The Field, Textarea and Button they are used with in this guide are free.

  • Rating
  • Reviews
  • Forms
  • Accessibility
  • React

Share

SR

About the author

Serban Rusu

Founder of Wingo UI

Serban Rusu founded Wingo UI. He builds its component library, CLI and MCP server, and writes about React interfaces for phones and AI coding agents.

More from Serban
Keep reading

Related posts

All posts
Component guides

Embla Carousel React: Accessible Slides, No Layout Shift

Build an embla carousel react component for photos, listings, testimonials and onboarding, with keyboard controls, pausable autoplay and no layout shift.

SRSerban Rusu·Oct 19, 2026·9 min read
Component guides

React Animated Number Counter: Rolling Odometer Digits

Build a React animated number counter that rolls each digit like an odometer, takes its separators from Intl, holds its width and respects reduced motion.

SRSerban Rusu·Oct 19, 2026·9 min read
Component guides

React Audio Player with Waveform: Scrub, Seek, Peaks

Build a React audio player with waveform scrubbing for podcasts, chat voice notes and call logs, with keyboard seek, precomputed peaks and no layout shift.

SRSerban Rusu·Oct 19, 2026·9 min read
Newsletter

Get new posts by email

New guides, tutorials and comparisons from the Wingo UI blog, sent when they are published.

No spam. Unsubscribe at any time.

WingoUI

Animated, configurable, mobile-first React components and blocks. Copy the source, make it yours, and let your coding agent build with it.

Product

  • Components
  • Templates
  • Pricing
  • AI agents
  • Theme generator

Resources

  • Docs
  • Blog
  • Changelog
  • Changelog RSS
  • llms.txt

Legal

  • Terms
  • Privacy
  • Refunds
  • License
  • Imprint

Component categories

  • Buttons & Actions
  • Inputs
  • Forms
  • Navigation
  • Overlays
  • Feedback
  • Data Display
  • Tables & Lists
  • Charts & Stats
  • Layout
  • Media
  • AI Kit
  • Text & Effects
  • Mobile
  • Commerce
  • Marketing Sections
  • Blocks
  • Hooks & Utilities

© 2026 Wingo UI

Wingo UI