Rating
Free · MITReact Native · ExpoStars (or any symbol) you tap or drag across: the fill sweeps from the old rating to the new one and every symbol it crosses pops on its own beat; half steps optional, and a read-only variant shows exact fractions with a value and a count.
Installation
$ npx shadcn@latest add https://goodui.dev/native/r/rating.jsonThen run npx expo install --fix so react-native-gesture-handler, react-native-reanimated, react-native-svg match your Expo SDK. Files land in components/goodui-native/rating.
Usage
import { useState } from "react";
import { Rating } from "@/components/goodui-native/rating/rating";
export function RateStay() {
const [stars, setStars] = useState(0);
return (
<Rating
size="lg"
value={stars}
onValueChange={setStars}
onValueCommit={(v) => saveReview({ stars: v })}
labels={["Terrible", "Bad", "Okay", "Good", "Great"]}
accessibilityLabel="Your stay"
/>
);
}When to use
- Asking for a review: a stay, a ride, an order, a support conversation.
- Showing an average score with its number of ratings in lists and product pages (readOnly with showValue and count).
- A small ordinal scale with a meaning per step, such as effort or difficulty, with labels.
- A continuous value or more than ten steps: use slider.
- Two or three named choices: use segmented-control or chip.
- A like or favorite: use like-button.
Examples
Half steps
<Rating allowHalf defaultValue={3.5} accessibilityLabel="Wine rating" />Read-only score in a list row
<Rating readOnly value={4.6} count={1284} showValue size="sm" />Custom symbol
<Rating
value={effort}
onValueChange={setEffort}
allowClear
icon={({ filled, color, size }) => <FlameIcon color={color} size={size} filled={filled} />}
/>API reference
| Prop | Type | Default |
|---|---|---|
| value The rating (controlled). Pair it with `onValueChange`. 0 means no rating yet. | number | — |
| defaultValue Initial rating when uncontrolled. Default 0. | number | 0 |
| onValueChange Called each time the rating changes, also while the finger slides across. | (value: number) => void | — |
| onValueCommit Called once when a tap or a drag ends, with the final rating. Save it here. | (value: number) => void | — |
| max Number of symbols. Default 5. | number | 5 |
| allowHalf Half steps (3.5). Read-only ratings always show the exact fraction. | boolean | false |
| allowClear Tapping the current rating clears it back to 0. Default `false`. | boolean | false |
| readOnly Display only: shows fractional values exactly (4.3), with optional `showValue` and `count`. | boolean | false |
| count Read-only: the number of ratings, shown as "(1,284)". | number | — |
| showValue Read-only: the numeric value before the symbols, one decimal. | boolean | false |
| labels One word per value, for example `["Terrible", "Bad", "Okay", "Good", "Great"]`. Shown beside the symbols and read as the value. | string[] | — |
| size Symbol size: 16 (`sm`, for lists), 32 (`md`) or 44 pt (`lg`, for a review screen). | "sm" | "md" | "lg" | "md" |
| tone Fill color: the accent, or the foreground for a quieter rating. Use an amber ThemeProvider accent for gold stars. | "accent" | "neutral" | "accent" |
| icon A different symbol (heart, thumb, flame). Defaults to a star. | RatingIcon | StarIcon |
| disabled Dims the control and ignores presses. | boolean | false |
| haptic `false` silences the tick per step. | boolean | true |
| accessibilityLabel Screen reader name. Default "Rating" (the pack's `group`). | string | — |
| style Style for the outer container. | StyleProp<ViewStyle> | — |
| testID Identifier for end-to-end tests. | string | — |
Motion and haptics
- A tap sweeps the fill from the old rating to the new one in 90 to 420 ms depending on the distance; each symbol pops (a swell, a small tilt, then the bouncy spring) the moment the fill crosses one of its half steps, so 1 to 5 ripples left to right. Lowering the rating dips the emptied symbols instead.
- While dragging, the fill follows the finger step by step on a 120 ms timing, with the same pops.
- The label crossfades when the value changes.
- Reduced motion: the fill jumps to the new value, symbols do not pop, labels change without fading.
- Haptic: select each time the value changes, by tap, drag, keyboard or screen reader (haptic={false} turns it off)
- The fill and pops run on the UI thread: one shared level drives every symbol's clip width, and each symbol reacts to it in a worklet. React only re-renders when the snapped value changes.
Accessibility
- The input is one adjustable element (a slider on the web) with aria-valuemin 0, aria-valuemax, aria-valuenow and a value text such as '4 of 5, Good' or 'Not rated'.
- Screen readers step it with increment and decrement; on the web the arrow keys step it (mirrored in right-to-left layouts), Home and End jump to the ends.
- The touch area is 44 pt tall; dragging anywhere across the row sets the value, so small symbols stay easy to hit.
- Read-only ratings are one image labelled with the visible number first: '4.6 out of 5 stars, 1,284 ratings'.
- Labels beside the symbols are hidden from screen readers because the same word is in the value text.
Notes for AI
- Controlled: value + onValueChange (fires during a drag too). Save or send in onValueCommit, which fires once per tap or drag.
- 0 means not rated. allowClear lets a tap on the current rating return to 0; otherwise the lowest value is one step.
- allowHalf gives 0.5 steps for input. readOnly always shows the exact fraction of value (4.3 fills 30 % of the fifth star).
- tone is 'accent' or 'neutral'. For gold stars set an amber accent on ThemeProvider; do not pass hex colors.
- icon receives { filled, color, size } and must draw the filled and empty look; the component clips it for halves.
- Sizes are sm 16 (lists, display), md 32 and lg 44 (review screens).
Related
Single and range sliders whose thumbs follow the finger 1:1 and settle onto the nearest step on release, with a value bubble that grows out of the thumb while dragging and optional step ticks that tick.
A like toggle with one moment of delight: the heart squashes and springs back filled, a ring expands and particles burst while the count rolls; it updates optimistically and rolls back if the request fails.
Two to five views of the same thing with an elastic highlight that stretches toward the new segment, can be dragged, and ticks at every boundary. Includes a billing toggle.