Vesture

Inputs

Rating

A star rating input built on native radio buttons, plus a read-only display mode for showing an average rating.

Rating

Preview

Click a star, or the left half of one for a half rating.

Usage

tsx
import { Rating } from "@vesture/react";

function Example() {
  const [rating, setRating] = useState(0);
  return (
    <Rating
      aria-label="Rate this product"
      allowHalf
      value={rating}
      onChange={setRating}
    />
  );
}

// Displaying someone else's average rating:
// <Rating readOnly value={4.2} />

Behavior

  • Renders one native radio per star sharing a single (auto-generated, or explicit name) group — arrow keys move between whole stars using the browser's native radio-group focus behavior, so this is real form-participating input, not a div reimplementing keyboard handling.
  • Hovering previews the rating up to and including the hovered star; the preview clears on mouse leave and the checked value's fill returns.
  • allowHalf doubles the granularity: clicking the left half of a star commits a half value, the right half commits a whole value. Shift+ArrowRight/Left move by half a star on the keyboard, since a native radio has no concept of "half checked".
  • readOnly renders max star outlines with a genuine partial-fill overlay per star (4.2/5 fills the 5th star to exactly 20%, it isn't rounded to 4) and swaps to role="img" with no inputs at all — for displaying an aggregate rating from other users' data.

Props

PropTypeDefaultDescription
value / defaultValue / onChangenumberControlled / uncontrolled rating value.
maxnumber5Number of stars.
allowHalfbooleanfalseEnables half-star clicks and Shift+Arrow keyboard steps.
readOnlybooleanfalseRenders a static, non-interactive display with genuine partial fill for non-integer values.
disabledbooleanDisables all stars; native radios stop responding to click and keyboard.
namestringRadio group name. Auto-generated via useId when omitted, so multiple Rating instances on one page never collide.
aria-labelstringRequired in practice — there's no visible text label by default.