Rating
Free · MITStar, heart, circle, bolt, diamond or custom-icon rating in solid, soft, outline, glow and neo styles: half steps, hover preview, clear, animated clip fill with pop or wave, value, count and word labels, read-only exact averages, RTL fill and arrow flipping, with radiogroup or slider semantics.
Installation
$ npx shadcn@latest add https://goodui.dev/r/rating.jsonThe file lands in components/goodui/rating.tsx and is yours to edit. With the @goodui registry added, npx shadcn@latest add @goodui/rating works too.
Usage
import * as React from "react"
import { Rating } from "@/components/goodui/rating"
export function ReviewForm() {
const [score, setScore] = React.useState(0)
return (
<form className="flex flex-col gap-3">
<Rating
aria-label="Rate your appointment"
value={score}
onValueChange={setScore}
size="lg"
itemLabels={["Poor", "Fair", "Good", "Great", "Excellent"]}
showLabel
name="score"
/>
<button disabled={!score}>Send review</button>
</form>
)
}When to use
- Collecting a review after an appointment, order or support chat.
- Showing an average next to a person, product or place (4.7 with 1,284 reviews), including exact fractions.
- Quick satisfaction scores with words per level (Poor … Excellent).
- Scores above 10 points or continuous values: use slider-tooltip or number-input.
- Yes/no feedback (helpful or not): use toggle-group with two items.
- Picking one of a few labeled options: use RadioGroup from checkbox, so every label is visible.
| If you need | Use |
|---|---|
| Review form | interactive with itemLabels and showLabel, animation="pop" or "wave" |
| Averages in lists and cards | readOnly size="xs" with showValue and count |
| Finer input | precision={0.5} (half steps, slider semantics) |
| Favorites or mood | icon="heart" with tone="danger" |
| Brand icon | icon={<YourIcon />}; lucide icons are filled with CSS |
| Playful brands | variant="neo" or "glow" |
Examples
Read-only average with count
<Rating value={4.7} readOnly size="xs" showValue count={1284} />Half steps
<Rating defaultValue={3.5} precision={0.5} showValue variant="glow" aria-label="Product quality" />Translated labels
<Rating
labels={{
group: "Bewertung",
item: (n) => `${n} Sterne`,
readOnly: (v, max) => `Bewertet mit ${v} von ${max}`,
countSr: (c) => `${c} Bewertungen`,
}}
/>API reference
| Prop | Type | Default |
|---|---|---|
| value Current rating (controlled); 0 means no rating. | number | — |
| defaultValue Initial rating when uncontrolled. | number | 0 |
| onValueChange Called with the new rating; 0 after clearing. | (value: number) => void | — |
| max Number of icons. | number | 5 |
| precision 1 for whole icons (radiogroup), 0.5 for half steps (slider). | 1 | 0.5 | 1 |
| readOnly Display only: no hover or focus, shows exact fractions. | boolean | — |
| disabled | boolean | — |
| clearable Picking the current value again, Backspace, Delete or 0 clears the rating. | boolean | true |
| hoverPreview Fill previews under the pointer before you click. | boolean | true |
| sound Plays a "tick" per icon under the pointer (pitched up along the row) and a "pop" on pick, when the visitor has sounds on (lib/goodui-sounds); a sound name replaces the pop. Off by default. | boolean | SoundName | — |
| icon Built-in icon name, or your own icon node (a lucide icon works: it gets filled with CSS). | RatingIcon | React.ReactNode | "star" |
| emptyIcon Different icon for the empty state; defaults to `icon`. | React.ReactNode | — |
| variant How icons are painted: solid (default), soft (tinted empties), outline (stroked empties), glow, or neo. | "solid" | "soft" | "outline" | "glow" | "neo" | "solid" |
| tone Fill color. Defaults to warning, the classic gold. | "primary" | "neutral" | "success" | "warning" | "danger" | "info" | "warning" |
| size | "xs" | "sm" | "md" | "lg" | "xl" | "md" |
| animation What moves when the rating changes. Reduced motion turns all of it off. | "none" | "fill" | "pop" | "wave" | "pop" |
| showValue Shows the number ("4.5") after the icons. | boolean | — |
| count Review count shown after the value, e.g. 1284 → "(1,284)". | number | — |
| itemLabels Word per icon ("Poor" … "Excellent"); read with the radios and shown when showLabel is set. | string[] | — |
| showLabel Shows the word for the current or hovered value after the icons. | boolean | — |
| name Form field name (renders a hidden input with the number). | string | — |
| iconsClassName Class for the icon row. | string | — |
| labels Text for screen readers and the count; pass translations here. | Partial<RatingLabels> | — |
Also accepts every <div> attribute.
Accessibility
| → / ↑ | Raise by one step (← in RTL). |
| ← / ↓ | Lower by one step (→ in RTL); reaches 0 only when clearable. |
| Home / End | Lowest step / max. |
| 1 – 9 | Set that rating directly. |
| 0 / Backspace / Delete | Clear the rating (clearable). |
| Space / Enter | Whole steps: pick the focused icon (again clears it when clearable). |
| Tab | One tab stop for the whole control (roving tabindex). |
- Whole steps render role="radiogroup" with one role="radio" per icon, aria-checked, roving tabindex and names like "4 stars, Great".
- Half steps render one role="slider" with aria-valuenow and aria-valuetext ("3.5 out of 5"), since a radio per half icon reads badly.
- readOnly renders role="img" named "Rated 4.7 out of 5"; the visible count is hidden from screen readers and replaced by "1,284 reviews".
- Pass aria-label or aria-labelledby to say what is being rated; the default name is "Rating". Every built-in string goes through labels.
- name renders a hidden input with the number for native forms.
Motion
- fill: the icon fill grows from the inline start with a clip-path transition (280 ms), also while previewing on hover.
- pop: fill plus the picked icon springs to 1.32× with a slight tilt and back (320 ms). wave: every filled icon pops in turn, 55 ms apart.
- The hovered icon scales to 1.14 (180 ms). none is static.
- Reduced motion: transitions, hover scale and pops are off; values still update instantly.
- Pops use the Web Animations API on the icon elements, so they cost no React renders. Read-only ratings attach no pointer or keyboard handlers.
Notes for AI
Coding agents read these rules through MCP and llms.txt, or paste this page with Copy page.
- value is a number from 0 to max; 0 means no rating. onValueChange receives 0 after clearing.
- Use readOnly for averages; it shows exact fractions (4.3 fills 30% of the fifth star) regardless of precision.
- precision is 1 or 0.5 only.
- Pass icon as a name (star, heart, circle, bolt, diamond) or a node; do not draw your own stars around it.
- Use tone for color (warning is the classic gold default); do not wrap it in a text color class.
FAQ
Does the fill follow right-to-left layouts?
Yes. The fill grows from the inline start, so under dir="rtl" it runs right to left, half clicks use the right half as the lower value, and the arrow keys flip.
Can I use emoji or my own SVG?
Any React node works as icon. SVGs are filled through CSS fill and stroke, so single-color icons look right; multi-color emoji only clip, they do not recolor.
Related
Single (radiogroup) or multiple (aria-pressed) toggle buttons in outline, soft, solid, segmented, neo and glass styles with a sliding, fading or popping active marker, text or icon items, tones, sizes, shapes, shadows, attached or spaced, vertical, full width, disabled items and roving arrow-key focus that flips in RTL.
Checkbox and RadioGroup on real inputs with default, filled, outline, circle, neo and whole-card variants, draw, pop and bounce animations, tones, sizes, shadows, indeterminate, invalid and descriptions.
Single or range slider built from scratch with pointer and keyboard control, step snapping, marks and a value bubble that scales in while dragging.
Numeric spinbutton with split, end or stacked steppers, press-and-hold acceleration, min/max/step and large steps, Intl currency, percent and unit formatting over a raw value, arrow, PageUp/PageDown, Home/End and focused-wheel stepping, slide or pop step feedback and an invalid state, in the six input variants with tones, sizes, shapes and shadows.
KPI card with seven variants, tones, shadows and sizes: count-up or rolling NumberFlow values, auto-toned delta badges (invertible for no-show rates), line, area or bar sparklines that draw in, icons, footers and a skeleton state.