Skip to content

Rating

A star rating. As an input it is a radio group of stars; with isReadOnly it is a display like "4.5 out of 5 stars" with an optional count.

Inputv0.1.0experimentalWCAG 2.2 AAView spec

You rated 3 out of 5

import { useState } from "react";
import { Rating } from "@rdloom/react";

export default function RatingBasicExample() {
  const [value, setValue] = useState(3);

  return (
    <div className="flex flex-col items-center gap-3 p-6">
      <Rating label="Rating" value={value} onChange={setValue} clearable />
      <p className="text-sm" aria-live="polite">
        {value === 0 ? "No rating yet" : `You rated ${value} out of 5`}
      </p>
    </div>
  );
}

Installation

npx rdloom add rating

Copies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes. It needs react-aria-components; add --install to install them.

Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/rating.json

Works, but without upgrade tracking.

Usage

import { Rating } from "@rdloom/react";

<div className="flex flex-col items-center gap-3 p-6">
  <Rating label="Rating" value={value} onChange={setValue} clearable />
  <p className="text-sm" aria-live="polite">
    {value === 0 ? "No rating yet" : `You rated ${value} out of 5`}
  </p>
</div>

Read only with count

1,284 ratings96 reviews
import { Rating } from "@rdloom/react";

export default function RatingReadOnlyWithCountExample() {
  return (
    <div className="flex flex-col items-center gap-3 p-6">
      <Rating label="Average rating" value={4.5} allowHalf isReadOnly count={1284} />
      <Rating label="Average rating" value={3.8} isReadOnly count={96} countLabel="reviews" size="sm" />
    </div>
  );
}

Half stars

3.5 out of 5

import { useState } from "react";
import { Rating } from "@rdloom/react";

export default function RatingHalfStarsExample() {
  const [value, setValue] = useState(3.5);

  return (
    <div className="flex flex-col items-center gap-3 p-6">
      <Rating label="Rating" allowHalf value={value} onChange={setValue} />
      <p className="text-sm" aria-live="polite">
        {value} out of 5
      </p>
    </div>
  );
}

Sizes

import { Rating } from "@rdloom/react";

export default function RatingSizesExample() {
  return (
    <div className="flex flex-col items-center gap-4 p-6">
      <Rating label="Small rating" size="sm" defaultValue={2} />
      <Rating label="Medium rating" size="md" defaultValue={3} />
      <Rating label="Large rating" size="lg" defaultValue={4} />
    </div>
  );
}

In a form

 
import { useState } from "react";
import { Form, FormRating, FormSubmitButton, FormTextField } from "@rdloom/react";

export default function RatingInAFormExample() {
  const [sent, setSent] = useState<string>();

  return (
    <div className="flex min-w-0 max-w-full justify-center p-6">
      <Form defaultValues={{ comment: "", stars: 0 }} onSubmit={(values) => setSent(`Thanks: ${values.stars} stars`)} className="flex w-80 max-w-full flex-col gap-4">
        <FormRating name="stars" label="Rating" isRequired requiredMessage="Choose a rating" />
        <FormTextField name="comment" label="Comment" multiline />
        <FormSubmitButton>Send review</FormSubmitButton>
        <p className="text-sm" aria-live="polite">
          {sent ?? ""}
        </p>
      </Form>
    </div>
  );
}

API Reference

Defined by the spec. Components also accept the props of the React Aria component they wrap.

PropTypeDefault
labelrequired

Name of what is rated, e.g. "Rating" or "Service". Screen readers hear it with the range: "Rating, 1 to 5 stars".

stringnone
value

Controlled value. 0 means no rating.

numbernone
defaultValue

Initial value when uncontrolled. 0 means no rating.

number0
onChange

Called with the new value, 1 to max (halves with allowHalf), or 0 when cleared.

(value: number) => voidnone
max

Number of stars.

number5
allowHalf

Lets people choose half stars, and shows halves when read-only.

booleanfalse
size

Size of the stars.

"sm" | "md" | "lg""md"
isReadOnly

Shows the value as an image with a text alternative instead of an input.

booleanfalse
isDisabled

Prevents interaction and dims the stars.

booleanfalse
clearable

Adds a Clear button so a chosen rating can be taken back.

booleanfalse
count

Read-only only: how many ratings the value comes from, shown as text next to the stars.

numbernone
countLabel

The word shown after the count.

string"ratings"
isLabelHidden

Hides the visible label. It still names the group for screen readers.

booleanfalse
description

Help text under the stars.

stringnone
errorMessage

Shown under the stars when isInvalid is true.

stringnone
isInvalid

Marks the rating as wrong and shows errorMessage.

booleannone
name

Submits the value with a form under this name.

stringnone

Accessibility

Role radiogroup, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.

Keyboard

  • Tab moves to the stars (the chosen one, or the first)
  • Right and Down Arrow choose the next star; Left and Up Arrow choose the previous (in a right-to-left page the horizontal arrows swap)
  • With allowHalf each arrow press moves by half a star
  • The Clear button is a normal button after the stars

Screen readers announce

  • Focusing the group reads "Rating, 1 to 5 stars, radio group" and the chosen star, "4 stars, 4 of 5"
  • Arrow keys read the new star as it is chosen
  • A read-only rating reads as an image: "4.5 out of 5 stars", then the count text

What your code must do

  • The group is a radio group named "<label>, 1 to <max> stars" and each star is a radio named "3 stars" ("3.5 stars" for halves)
  • A chosen star is filled and an unchosen one is an outline, so the value never depends on color
  • Hovering previews the value; nothing is chosen until a click or key
  • Read-only shows role img named "4.5 out of 5 stars"; the count is real text beside it
  • Each star's target is at least 24px

Guidelines

Use it when

  • Asking for a quick opinion of a product, service or article
  • Showing an average rating on a card or a list

Avoid it when

  • A precise number: use NumberField or Slider
  • A choice with named levels (poor, good, great): use RadioGroup or SegmentedControl

Don't

  • Showing a read-only rating with no count or context
  • Using only color to tell chosen stars from empty ones
  • Making a rating required with no way to take it back

Design tokens

The semantic tokens this component uses. Change them once and every component follows; see Design tokens.

  • --rd-color-action-primary
  • --rd-color-border-strong
  • --rd-color-text-default
  • --rd-color-text-muted
  • --rd-color-feedback-danger
  • --rd-color-focus-ring