Gecko UIGecko UI

Rating

A rating, picked or shown

Rating

A rating, picked or shown.

Installation

import { Rating } from '@geckoui/geckoui';

Basic Usage

value: 3

const [score, setScore] = useState(3);

<Rating value={score} onChange={setScore} aria-label="Score" />

Picking the rating it already has sets it back to 0, which is the only way to undo a mis-click with a mouse. clearable={false} turns that off.

Props API

PropTypeDefaultDescription
valuenumberrequiredHow many are filled. Any fraction is drawn exactly
onChange(value: number) => void-Called with the new rating, or 0 when the current one is picked again
maxnumber5How many icons there are
precisionnumber1What a click lands on, as a fraction of one icon
clearablebooleantrueWhether picking the current rating again sets it to zero
readOnlybooleanfalseShown rather than picked
disabledbooleanfalse
iconReactNodea starThe icon
emptyIconReactNodeiconA different icon for the empty part
getLabel(value: number) => string`${value} of ${max}`What each one is called, for a screen reader
namestringgeneratedTies the radios together
aria-labelstring-What the whole thing is called
colorkeyof RatingColorMap'gold'gold, or any of the six semantic colours
sizekeyof RatingSizeMap'md'
classNamestring-

Examples

Precision

precision 1
precision 0.5
precision 0.25
precision 0.1

value: 3.5

<Rating value={score} onChange={setScore} />                  {/* whole icons */}
<Rating value={score} onChange={setScore} precision={0.5} />  {/* halves */}
<Rating value={score} onChange={setScore} precision={0.1} />  {/* tenths */}

precision decides what a click lands on, never what is drawn. All four above share one value, and each draws it identically — they differ only in what you can pick.

The arrow keys step by precision too, which is how a tenth stays reachable where a two-pixel pointer target is not.

Shown rather than picked

4.3
2.7
5
0
<Rating value={4.3} readOnly aria-label="4.3 out of 5" />

A fraction is drawn exactly whether the rating can be picked or not, so an average reads as it is rather than being rounded to something the reader was never told. readOnly only takes the interaction away.

Other icons

{/* one icon, recoloured */}
<Rating value={hearts} onChange={setHearts} color="error" icon={<HeartIcon />} />

{/* a different shape for the empty part */}
<Rating value={4} onChange={setValue} icon={<StarSolid />} emptyIcon={<StarOutline />} />

icon alone is used for both halves of each one, filled and empty, with only the colour between them. Give emptyIcon as well when the empty state is a different shape, like an outline against a solid.

Sizes

Colours

Stars are gold by default, and the six semantic colours are there for the times a rating means something else — a red heart, a green score.

The gold is a fixed colour rather than a theme token, because gold is gold in either theme. It is a shade below a true #FFD700 on purpose: at that lightness a filled star and an empty one differ only in saturation unless the empty is washed out to nearly white, which reads worse on a light background than the problem it solves.

The keyboard

KeyDoes
→ ↑On one step
← ↓Back one step, and to nothing from the first
HomeTo nothing
EndTo the top

Styling with CSS

VariableDefaultApplies to
--gecko-rating-accentper colorThe filled part
--gecko-rating-goldoklch(0.7845 0.1633 68.5)The default gold
--gecko-rating-empty--color-surface-activeThe empty part
--gecko-rating-sizeper sizeEach icon
--gecko-rating-gap0.125remBetween them

Class names and data attributes

  • GeckoUIRating - The group, with data-color, data-size, data-readonly and data-disabled
  • GeckoUIRating__icon - One icon, with data-filled when it is full
  • GeckoUIRating__icon__empty - The empty copy underneath
  • GeckoUIRating__icon__fill - The filled copy, clipped to however much was earned
  • GeckoUIRating__inputs - The radios, kept out of sight

Each icon is two copies of the same glyph stacked, the filled one clipped to a width. That is what lets a fraction be a fraction rather than being rounded to a whole.

Accessibility

A rating is a one-of-many choice, so it is built as a radio group: visually hidden radios carry the semantics and the arrow keys, and post in a plain form. The icons are only what is seen.

Each value is named "1 of 5", "2 of 5" and so on. Name the group with aria-label, and override the per-value name with getLabel:

<Rating value={score} onChange={setScore} aria-label="Rate this article" getLabel={(v) => `${v} stars`} />

The focus ring goes round the whole group, since the radios themselves are out of sight.

  • RHFRating - The same rating, wired to React Hook Form
  • Progress - For showing a number rather than picking one
  • Radio - For a one of many choice that is not a rating