Rating

Material Design 3 rating component with stars, hearts, and customizable icons

Rating

Ratings provide insight regarding others’ opinions and experiences, and can allow the user to submit their own rating. @duskmoon-dev/core provides a flexible and accessible rating component.

Basic Usage

Basic Rating

β˜† β˜† β˜† β˜† β˜†

Filled Rating

Display a rating value with filled stars:

Filled Rating

β˜… β˜… β˜… β˜† β˜†

Color Variants

Primary (Default)

Primary Rating

β˜… β˜… β˜… β˜† β˜†

Secondary

Secondary Rating

β˜… β˜… β˜… β˜† β˜†

Tertiary

Tertiary Rating

β˜… β˜… β˜… β˜† β˜†

The warning variant uses a golden/amber color, which is typical for rating displays:

Warning Rating

β˜… β˜… β˜… β˜… β˜†

Sizes

Four size variants are available:

Rating Sizes

β˜… β˜… β˜… β˜† β˜†
β˜… β˜… β˜… β˜† β˜†
β˜… β˜… β˜… β˜† β˜†
β˜… β˜… β˜… β˜† β˜†

Half Stars

Display precise ratings with half-filled stars:

Half Stars

β˜… β˜… β˜… β˜† β˜†

Read-Only Rating

Display a non-interactive rating:

Read-Only Rating

β˜… β˜… β˜… β˜… β˜†

Disabled Rating

Display a disabled rating:

Disabled Rating

β˜… β˜… β˜… β˜† β˜†

With Label

Add descriptive text to your rating:

Rating with Label

Product Quality
β˜… β˜… β˜… β˜… β˜†

With Value Display

Show the numeric rating value:

Rating with Value

β˜… β˜… β˜… β˜… β˜† 4.0

With Review Count

Display the number of reviews:

Rating with Review Count

β˜… β˜… β˜… β˜… β˜† 4.5 (234 reviews)

With Description

Add contextual descriptions that update with the rating:

Rating with Description

β˜… β˜… β˜… β˜… β˜†
Excellent

Interactive Rating

Allow users to select their own rating:

Interactive Rating

β˜† β˜† β˜† β˜† β˜†

Clearable Rating

Add a clear button to reset the rating:

Clearable Rating

β˜… β˜… β˜… β˜† β˜†

Vertical Layout

Display rating in a vertical orientation:

Vertical Rating

β˜… β˜… β˜… β˜† β˜†

Heart Icons

Use heart icons instead of stars:

Heart Rating

β™₯ β™₯ β™₯ β™‘ β™‘

Precision Variants

Control the precision of ratings:

Precision Variants

β˜… β˜… β˜… β˜† β˜†
β˜… β˜… β˜† β˜† β˜†
β˜… β˜… β˜… β˜† β˜† 3.7

Best Practices

Accessibility

  • Use appropriate ARIA labels for interactive ratings
  • Ensure keyboard navigation is supported with tabindex
  • Provide role="radio" or role="radiogroup" for selectable ratings
  • Include visible labels or descriptions when possible

Accessible Rating

β˜† β˜† β˜† β˜† β˜†

Display vs. Input

  • Use read-only ratings for displaying existing ratings
  • Use interactive ratings for collecting user input
  • Consider showing aggregate ratings separately from user input

Display vs Input

β˜… β˜… β˜… β˜† β˜† 3.5 (128 reviews)
Your rating:
β˜† β˜† β˜† β˜† β˜†

Visual Clarity

  • Use the warning (golden) color for traditional star ratings
  • Provide clear visual feedback on hover and selection
  • Show the current value for clarity
  • Use half stars for more precise ratings

Context

Always provide context for ratings:

Rating with Context

Product Review

Overall
β˜… β˜… β˜… β˜… β˜† 4.5
Quality
β˜… β˜… β˜… β˜… β˜…
Value
β˜… β˜… β˜… β˜… β˜†

Framework Examples

React

interface RatingProps {
  value: number;
  max?: number;
  size?: 'sm' | 'md' | 'lg' | 'xl';
  color?: 'primary' | 'secondary' | 'tertiary' | 'warning';
  readonly?: boolean;
  onChange?: (value: number) => void;
}

export function Rating({
  value,
  max = 5,
  size = 'md',
  color = 'warning',
  readonly = false,
  onChange
}: RatingProps) {
  const handleClick = (index: number) => {
    if (!readonly && onChange) {
      onChange(index + 1);
    }
  };

  const classes = [
    'rating',
    size !== 'md' && `rating-${size}`,
    color !== 'primary' && `rating-${color}`,
    readonly && 'rating-readonly',
    !readonly && 'rating-interactive'
  ].filter(Boolean).join(' ');

  return (
    <div className={classes}>
      {Array.from({ length: max }, (_, i) => (
        <span
          key={i}
          className={`rating-item ${i < value ? 'rating-item-filled' : ''}`}
          onClick={() => handleClick(i)}
          tabIndex={readonly ? -1 : 0}
          role={readonly ? undefined : 'radio'}
          aria-label={`${i + 1} star${i > 0 ? 's' : ''}`}
        >
          {i < value ? 'β˜…' : 'β˜†'}
        </span>
      ))}
    </div>
  );
}

// Usage
<Rating value={4} onChange={(val) => console.log('Rating:', val)} />
<Rating value={3.5} readonly color="warning" />

Vue

<template>
  <div :class="classes">
    <span
      v-for="(_, i) in max"
      :key="i"
      :class="['rating-item', { 'rating-item-filled': i < value }]"
      @click="handleClick(i)"
      :tabindex="readonly ? -1 : 0"
      :role="readonly ? undefined : 'radio'"
      :aria-label="`${i + 1} star${i > 0 ? 's' : ''}`"
    >
      {{ i < value ? 'β˜…' : 'β˜†' }}
    </span>
  </div>
</template>

<script setup>
import { computed } from 'vue';

const props = defineProps({
  value: { type: Number, required: true },
  max: { type: Number, default: 5 },
  size: { type: String, default: 'md' },
  color: { type: String, default: 'warning' },
  readonly: { type: Boolean, default: false }
});

const emit = defineEmits(['update:value']);

const classes = computed(() => [
  'rating',
  props.size !== 'md' && `rating-${props.size}`,
  props.color !== 'primary' && `rating-${props.color}`,
  props.readonly && 'rating-readonly',
  !props.readonly && 'rating-interactive'
].filter(Boolean).join(' '));

const handleClick = (index) => {
  if (!props.readonly) {
    emit('update:value', index + 1);
  }
};
</script>

<!-- Usage -->
<Rating :value="4" @update:value="handleRating" />
<Rating :value="3.5" readonly color="warning" />

API Reference

Class Names

ClassDescription
.ratingBase rating container (required)
.rating-itemIndividual rating icon (star, heart, etc.)
.rating-item-filledFilled/selected rating item
.rating-item-primary-filledPrimary color filled item
.rating-item-halfHalf-filled rating item
.rating-primaryPrimary color variant
.rating-secondarySecondary color variant
.rating-tertiaryTertiary color variant
.rating-warningWarning/golden color (recommended)
.rating-smSmall size (1rem)
.rating-lgLarge size (2rem)
.rating-xlExtra large size (2.5rem)
.rating-readonlyNon-interactive display mode
.rating-disabledDisabled state
.rating-interactiveInteractive/selectable mode
.rating-labelLabel container for rating
.rating-valueNumeric value display
.rating-countReview count display
.rating-descriptionDescription text
.rating-with-descriptionContainer with description
.rating-verticalVertical layout
.rating-clearableRating with clear button
.rating-clear-btnClear button element
.rating-heartHeart icon variant
.rating-precision-fullFull star precision
.rating-precision-halfHalf star precision
.rating-precision-decimalDecimal precision

Combinations

You can combine classes for different effects:

Class Combinations

β˜… β˜… β˜… β˜† β˜†
β˜† β˜† β˜† β˜† β˜†
  • Button - Action triggers
  • Badge - Status indicators
  • Chip - Compact elements

See Also