# Rating

> Star rating with one fill that slides across every star, so half steps and pointer previews come free.

- Page: https://ui.devigner.cc/components/rating
- Category: Marketing
- Requirements: React 18 or 19, Tailwind CSS v4
- Install: `npx devignerui add rating` (writes components/ui/rating.tsx)
- Packages it needs: cn, motion, devignerui

## What the demo shows

The live demo is a large five-star rating at 3.5. Move across it and the fill follows the pointer in half stars; click to set it, and the number and its word update underneath.

## When to use it

- Asking for a quick score: reviews, feedback after a task, rating a result.
- Showing an average next to a product or item, with readOnly.

## When to reach for something else

- Precise numbers or scales longer than about ten steps. Use a slider or a number field.
- Yes or no feedback. Use two buttons, such as thumbs up and down.

## Usage

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

<Rating aria-label="Rating" defaultValue={4} />
```

Custom composition:

```tsx
<Rating aria-label="Rating" step={0.5} size="lg" value={score} onValueChange={setScore} />
```

### Ask for feedback and send it

A controlled rating that submits with a form under its name.

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

export function Feedback({ send }: { send: (score: number) => void }) {
  const [score, setScore] = useState(0);
  return (
    <form
      onSubmit={(e) => {
        e.preventDefault();
        send(score);
      }}
    >
      <p id="rate-label">How was the checkout?</p>
      <Rating aria-labelledby="rate-label" name="score" value={score} onValueChange={setScore} clearable />
      <button type="submit" disabled={score === 0}>Send</button>
    </form>
  );
}
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| value | `number` | - | Controlled rating, from 0 to count. Pass with onValueChange. |
| defaultValue | `number` | 0 | Rating on first render when uncontrolled. |
| onValueChange | `(value: number) => void` | - | Called with the new rating on click, tap or key press. |
| count | `number` | 5 | How many stars. |
| step | `1 \| 0.5` | 1 | 1 for whole stars, 0.5 to allow halves. |
| size | `"sm" \| "md" \| "lg"` | "md" | Star size: 20, 28 or 36px. |
| clearable | `boolean` | false | Picking the current rating again clears it to 0. |
| readOnly | `boolean` | false | Shows the rating without taking input, such as a product's average. |
| disabled | `boolean` | false | Dims the stars and takes no input. |
| icon | `ReactNode` | a star | Replaces the star with your own shape, drawn in currentColor. |
| name | `string` | - | Form field name; the rating submits with the form. |
| valueText | `(value, count) => string` | "3 out of 5" | What screen readers hear for the rating. |
| classNames | `RatingClassNames` | - | Slot classes: empty (the unfilled shapes) and fill (the filled ones). |

## Keyboard

| Keys | Action |
| --- | --- |
| Right / Up arrows | Raise the rating by one step. |
| Left / Down arrows | Lower it by one step. |
| Home / End | Set it to 0 or to the top. |
| 1 to 9 | Jump straight to that many stars. |

## Accessibility

- The rating is one role="slider" with aria-valuemin, aria-valuemax and aria-valuenow, and reads as "3.5 out of 5" by default (valueText).
- Give it a name with aria-label or aria-labelledby, such as "Rate this recipe".
- readOnly sets aria-readonly and disabled sets aria-disabled; neither takes input.
- The stars themselves are hidden from screen readers; the slider carries the value.
- Honors prefers-reduced-motion and an ancestor <MotionConfig reducedMotion="always">, so an in-app motion switch works too.

## Theming

- The fill is warning and the empty stars are foreground at 12%. Change them through classNames.fill and classNames.empty, such as text-primary.
- icon swaps the star for any shape drawn in currentColor: a heart, a flame, a dot.
- size picks 20, 28 or 36px stars with the gaps to match.
- The fill follows the pointer on SPRING_MOUSE and settles on SPRING_LAYOUT when you commit; the star you land on pops with SPRING_PRESS.

## Edge cases

- Values snap to the step and the range, so 3.3 with step 0.5 shows 3.5, and anything over count shows count.
- On touch, dragging across the stars previews and lifting your finger commits.
- Without clearable there is no way to go back to 0 by pointer; Home on the keyboard still sets 0.
- The fill grows from the left, also in right-to-left layouts.

## Troubleshooting

**I can't set half stars by clicking.**
Halves need step={0.5}. With the default step of 1 every click rounds up to a whole star.

**The stars are invisible.**
They are colored with the warning and foreground tokens. Define them, or set your own colors through classNames.

**The component renders with no background or the wrong colors.**
Colors use the standard shadcn/ui tokens only (background, foreground, primary, secondary, muted, accent, border, input, ring, destructive), so a project set up with shadcn/ui needs nothing extra and the component follows its theme, dark mode included. Without shadcn/ui, define those CSS variables for :root and .dark and map them in your Tailwind v4 @theme, or run npx shadcn init.
