# 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.

- Type: React component (Inputs)
- Access: Pro (the source needs a Wingo UI Pro plan, see https://wingo-ui.com/pricing)
- Version: 1.0.0
- Install: `npx wingo-ui@latest add rating`
- Docs: https://wingo-ui.com/components/rating

## Interaction

Click or tap an icon to rate; with allowHalf the left half of an icon gives a half value. With a mouse the icons preview the rating under the pointer (the part beyond the chosen value dimmed) and the label follows it. Clicking the chosen value again clears it when clearable. On a phone, drag a finger across the icons to scrub and lift it to commit; every icon is a 44px target and the drag never scrolls the page. On commit the icons fill with a small staggered pop, and lowering fades the removed fill. The group is one slider: Tab to it for a focus ring, then Right / Up adds one (a half with allowHalf), Left / Down removes one (mirrored in right-to-left pages), PageUp / PageDown move a whole icon, Home clears (or goes to the lowest value), End jumps to the top, digits 1 to 9 pick a value directly, and 0, Backspace or Delete clear. Read-only ratings are a picture with a spoken summary ("Rated 4.8 of 5"). In the playground Send rating checks that a rating was chosen, pretends to send it and thanks you.

## Installation

```bash
npx wingo-ui@latest add rating
```

Pro item: run `npx wingo-ui@latest login` once with a Pro account. The CLI adds the files, their dependencies and a version record for updates.

With shadcn: `npx shadcn@latest add @wingo-ui/rating` (needs the @wingo-ui registry with your API key in components.json)

Files:

- `components/ui/rating.tsx`

npm dependencies: `npm i motion lucide-react`

Wingo UI dependencies (installed automatically):

- [Field](https://wingo-ui.com/components/field) ([Markdown](https://wingo-ui.com/components/field.md))
- [useControllableState](https://wingo-ui.com/components/use-controllable-state) ([Markdown](https://wingo-ui.com/components/use-controllable-state.md))
- [useLocale](https://wingo-ui.com/components/use-locale) ([Markdown](https://wingo-ui.com/components/use-locale.md))
- [Motion presets](https://wingo-ui.com/components/motion) ([Markdown](https://wingo-ui.com/components/motion.md))
- [Number format](https://wingo-ui.com/components/number-format) ([Markdown](https://wingo-ui.com/components/number-format.md))
- [Tones](https://wingo-ui.com/components/tones) ([Markdown](https://wingo-ui.com/components/tones.md))
- [UIProvider](https://wingo-ui.com/components/ui-config) ([Markdown](https://wingo-ui.com/components/ui-config.md))

## Usage

```tsx
import { useState } from "react"
import { Rating } from "@/components/ui/rating"

const LABELS = ["Very poor", "Poor", "Okay", "Good", "Excellent"]

export function SellerReview() {
  const [rating, setRating] = useState(0)
  return (
    <div className="flex flex-col gap-6">
      <Rating
        label="How was your experience?"
        name="rating"
        value={rating}
        onValueChange={setRating}
        labels={LABELS}
        showLabel
        emptyLabel="Tap a star"
        required
      />
      <Rating readOnly value={4.8} tone="warning" size="sm" showValue />
    </div>
  )
}
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `label?` | `ReactNode` | `""` | The field label, rendered as a span that names the icon group (a click on it focuses the group). |
| `description?` | `ReactNode` | `""` | Helper text under the icons, linked with aria-describedby. The error takes its place while it shows. |
| `error?` | `ReactNode` | `""` | Replaces the description with the animated error, tints the empty icons red and sets aria-invalid. |
| `required?` | `boolean` | `false` | The required mark after the label. The check itself belongs to your form (the playground blocks sending without a rating). |
| `invalid?` | `boolean` | `false` | The invalid look (red-tinted empty icons) and aria-invalid without a message. |
| `disabled?` | `boolean` | `false` | Dims to 50%, leaves the tab order and ignores pointer and keys. A disabled FieldGroup disables it too. |
| `readOnly?` | `boolean` | `false` | Display only: role="img" with a spoken summary, no pointer or keys, and fractions like 4.3 drawn proportionally. The number keeps one decimal ("4,8"). |
| `max?` | `number` | `5` | How many icons. Below 1 falls back to 5. The playground keeps its Romanian labels only at 5. |
| `allowHalf?` | `boolean` | `false` | Half values: the left half of an icon (right half in RTL) gives x.5, and the arrow keys move by 0.5. Ignored with icons. |
| `clearable?` | `boolean` | `true` | Choosing the current value again clears it, a scrub past the first icon clears, and 0 / Backspace / Delete clear from the keyboard. false keeps at least one step. |
| `size?` | `"sm" \| "md" \| "lg"` | `"md"` | Icons 16 / 24 / 32px with 2 / 4 / 6px between them, and the value and label type. On touch screens every icon is a 44px target. |
| `tone?` | `"neutral" \| "brand" \| "success" \| "warning" \| "danger" \| "info"` | `"neutral"` | The fill. neutral is black in light mode and white in dark mode; warning gives the classic amber stars. |
| `color?` | `string` | `""` | Any CSS color for the fill; replaces the tone. |
| `showLabel?` | `boolean` | `false` | The hovered or chosen value's label beside the icons (Very poor … Excellent). Needs labels. |
| `emptyLabel?` | `ReactNode` | `""` | What the label slot says while nothing is chosen, with showLabel. Empty shows nothing. |
| `showValue?` | `boolean` | `false` | The number beside the icons, through Intl: "4.5" in en-US, "4,5" in de-DE. It follows the hover preview. |
| `locale?` | `string` | `""` | Locale for the number. Empty uses the UIProvider locale, then the nearest LocaleProvider, then the page's language (en-US on the server). The demo passes en-US. |
| `name?` | `string` | `""` | Form field name: a hidden input submits the value ("0" when empty, "4.5" with halves), and a form reset puts defaultValue back. |
| `icon?` | `ReactNode` | `"<Star />"` | The icon repeated max times: any lucide icon (Heart, ThumbsUp). The fill layer paints it with fill-current. |
| `icons?` | `ReactNode[]` |  | One icon per value, e.g. Frown, Meh, Smile, Laugh. Only the chosen (or hovered) icon lights up, in the tone with a soft tone fill; no halves. A list shorter than max repeats its last icon. |
| `labels?` | `string[]` |  | One label per value (labels[0] is 1). Read as aria-valuetext and shown with showLabel. |
| `getValueText?` | `(value: number, max: number) => string` | `` "(v, m) => `${v} of ${m}`" `` | What screen readers hear for a value without a label (and for halves). |
| `getReadOnlyLabel?` | `(value: number, max: number) => string` | `` "(v, m) => `Rated ${v} of ${m}`" `` | The spoken name of a read-only rating; the value is rounded to one decimal. |
| `value?` | `number` |  | The controlled rating; 0 = none. A value between steps (4.3) is drawn proportionally and snaps on the next interaction. |
| `defaultValue?` | `number` | `0` | The uncontrolled start; a form reset returns to it. The playground starts its rating here. |
| `onValueChange?` | `(value: number) => void` |  | When a rating is committed: on release of a tap or scrub, and on every key press. |
| `id?` | `string` |  | The group's id. Defaults to useId(); the label points at it. |
| `fieldProps?` | `Partial<FieldProps>` |  | Anything else for the Field wrapper: optional, labelAction, orientation, labelWidth, hideLabel. |
| `classNames?` | `Partial<Record<"box" \| "root" \| "item" \| "icon" \| "fill" \| "empty" \| "value" \| "label" \| "field" \| "description" \| "error", string>>` |  | Extra classes for the inner parts: box (icons, number and label), root (the slider group), item (each cell), icon (the icon box), fill and empty (the two layers), value, label and the field parts. |
| `className?` | `string` |  | Classes for the outermost element: the Field root when the rating has a label, description or error, else the box. |

## Examples

- **Read-only in a seller card**: A proportional 4.8 in amber with the number beside it, en-US next to ro-RO.
- **Half values and sizes**: allowHalf with the warning tone at sm / md / lg; the three share one value.
- **Sentiment icons**: icons gives one face per value; only the chosen one lights up, with its label.
- **Custom icon**: Any lucide icon through icon: hearts in the danger tone with a label per value.
- **Required with an error**: The empty icons turn red and the error shows until a rating is picked.
- **Ten-point scale**: max={10} with showValue, small icons so the row fits a phone.
- **Custom color, brand and disabled**: A CSS color replaces the tone; disabled dims and ignores input.

## See also

- [Reviews](https://wingo-ui.com/components/reviews) ([Markdown](https://wingo-ui.com/components/reviews.md))
- [Emoji Reaction](https://wingo-ui.com/components/emoji-reaction) ([Markdown](https://wingo-ui.com/components/emoji-reaction.md))
- [Field](https://wingo-ui.com/components/field) ([Markdown](https://wingo-ui.com/components/field.md))
- [Slider](https://wingo-ui.com/components/slider) ([Markdown](https://wingo-ui.com/components/slider.md))
- [Textarea](https://wingo-ui.com/components/textarea) ([Markdown](https://wingo-ui.com/components/textarea.md))
- [Tones](https://wingo-ui.com/components/tones) ([Markdown](https://wingo-ui.com/components/tones.md))

---

Canonical: https://wingo-ui.com/components/rating
More components: https://wingo-ui.com/components · Index for agents: https://wingo-ui.com/llms.txt
