Rating
A composable, accessible Rating component for modern React applications.
tsx
import { Rating } from '@nofinite/nui';Interactive Preview
Loading preview...
A visual input component that allows users to select a rating value using icons (typically stars). It supports controlled and uncontrolled modes, fractional selection, keyboard interaction, and custom icon rendering.
Usage
Basic usage
tsx
import { Rating } from '@nofinite/nui';
export function Example() {
return <Rating defaultValue={3} />;
}Controlled usage
tsx
const [value, setValue] = useState(4);
<Rating value={value} onChange={setValue} />;Half rating
tsx
<Rating defaultValue={3.5} allowHalf />Read-only display
tsx
<Rating value={4.2} readOnly />Custom icons
tsx
<Rating icon={<HeartOutline />} iconFilled={<HeartFilled />} />Variants
Sizes
tsx
<Rating size="sm" />
<Rating size="md" />
<Rating size="lg" />Available variants
- sm
- md
- lg
Guidelines
- Use sm inside dense layouts (tables, cards)
- Use md as default
- Use lg for emphasis or hero sections
States
- Default
- Hover preview (temporary fill during pointer move)
- Focus visible (keyboard focus ring)
- Read-only
- Disabled
- Fractional display
- Controlled vs uncontrolled value
Keyboard Interaction
| Key | Behavior |
|---|---|
| ArrowRight / ArrowUp | Increase rating (step = 1 or 0.5) |
| ArrowLeft / ArrowDown | Decrease rating |
| Home | Set to minimum (0) |
| End | Set to maximum |
Component uses role="slider" semantics.
Accessibility
-
Uses slider pattern with:
aria-valueminaria-valuemaxaria-valuenowaria-disabledaria-readonly
-
Keyboard operable
-
Focus visible outline
-
Tab navigation disabled when readOnly or disabled
Best Practices
Do
- Use half rating when precision matters (reviews)
- Use readOnly for aggregated scores
- Keep max ≤ 10 to avoid cognitive overload
- Use custom icons for domain-specific ratings
Don’t
- Use rating as the only feedback control for critical flows
- Combine disabled and readOnly simultaneously unless intentional
- Allow fractional ratings without clear visual affordance
- Overuse large size in dense UI contexts
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
value | number | — | Controlled state value |
defaultValue | number | 0 | Uncontrolled initial value |
max | number | 5 | The maximum possible rating. Determines how many icons to render. Defaults to 5. |
onChange | ((value: number) => void) | — | Callback fired when a rating is selected |
icon | ReactNode | (
<svg width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"></polygon>
</svg>
) | Custom React node for the empty state |
iconFilled | ReactNode | (
<svg width="1em" height="1em" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"></polygon>
</svg>
) | Custom React node for the filled state |
size | enum | md | Size variant |
readOnly | boolean | false | Makes the rating strictly decorative |
disabled | boolean | false | Disables interactions and applies a muted style |
allowHalf | boolean | false | Enables fractional half-step selections (e.g., 3.5 stars) |