Skip to content

Rate Component ​

Overview ​

The Rate component is used for ratings, supporting half-star selection and auxiliary text prompts. It's an intuitive evaluation component commonly used in scenarios such as product reviews and user feedback.

Learning Objectives ​

  • Master the basic concepts and use cases of Rate
  • Learn how to use basic rating functionality
  • Understand rating state control and event handling
  • Master different styles and sizes of ratings
  • Learn to customize rating icons and colors
  • Understand half-star ratings and auxiliary text
  • Master the complete usage of the API

Basic Usage ​

Basic Rating ​

The simplest rating usage:

vue
<template>
  <div>
    <el-rate v-model="value1" />
    <p>Rating: {{ value1 }}</p>
    
    <el-rate v-model="value2" :max="10" />
    <p>Rating (out of 10): {{ value2 }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const value1 = ref(3)
const value2 = ref(7)
</script>

Disabled State ​

Use the disabled attribute to disable rating:

vue
<template>
  <div>
    <el-rate v-model="value1" disabled />
    <p>Disabled rating: {{ value1 }}</p>
    
    <el-rate v-model="value2" disabled show-text />
    <p>Disabled rating with text: {{ value2 }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const value1 = ref(3.5)
const value2 = ref(4)
</script>

Read-only State ​

Use the readonly attribute to set read-only state:

vue
<template>
  <div>
    <el-rate v-model="value1" readonly />
    <p>Read-only rating: {{ value1 }}</p>
    
    <el-rate v-model="value2" readonly show-score />
    <p>Read-only rating with score: {{ value2 }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const value1 = ref(4.5)
const value2 = ref(3.7)
</script>

Auxiliary Text ​

Display Text ​

Use the show-text attribute to display auxiliary text:

vue
<template>
  <div>
    <el-rate
      v-model="value1"
      show-text
    />
    <p>Current rating: {{ value1 }}</p>
    
    <el-rate
      v-model="value2"
      :texts="customTexts"
      show-text
    />
    <p>Custom text rating: {{ value2 }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const value1 = ref(3)
const value2 = ref(2)

const customTexts = [
  'Terrible',
  'Disappointing', 
  'Average',
  'Satisfactory',
  'Excellent'
]
</script>

Display Score ​

Use the show-score attribute to display the current score:

vue
<template>
  <div>
    <el-rate
      v-model="value1"
      show-score
    />
    <p>Display score: {{ value1 }}</p>
    
    <el-rate
      v-model="value2"
      show-score
      score-template="{value} points"
    />
    <p>Custom score template: {{ value2 }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const value1 = ref(4.5)
const value2 = ref(3.2)
</script>

Half-Star Rating ​

Use the allow-half attribute to support half-star ratings:

vue
<template>
  <div>
    <h4>Full-star rating</h4>
    <el-rate v-model="value1" />
    <p>Rating: {{ value1 }}</p>
    
    <h4>Half-star rating</h4>
    <el-rate v-model="value2" allow-half />
    <p>Rating: {{ value2 }}</p>
    
    <h4>Half-star rating + Display score</h4>
    <el-rate v-model="value3" allow-half show-score />
    <p>Rating: {{ value3 }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const value1 = ref(3)
const value2 = ref(3.5)
const value3 = ref(4.2)
</script>

Custom Icons ​

Using Icons ​

Use the icons attribute to customize icons for different levels:

vue
<template>
  <div>
    <h4>Custom icons</h4>
    <el-rate
      v-model="value1"
      :icons="customIcons"
      :void-icon="ChatDotRound"
      :colors="customColors"
    />
    <p>Rating: {{ value1 }}</p>
    
    <h4>Emoji rating</h4>
    <el-rate
      v-model="value2"
      :icons="faceIcons"
      :void-icon="ChatDotRound"
      :colors="['#99A9BF', '#F7BA2A', '#FF9900']"
    />
    <p>Rating: {{ value2 }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import {
  ChatDotRound,
  Star,
  StarFilled,
  Sunny,
  Moon
} from '@element-plus/icons-vue'

const value1 = ref(3)
const value2 = ref(2)

const customIcons = [Star, Star, StarFilled]
const customColors = ['#99A9BF', '#F7BA2A', '#FF9900']

const faceIcons = [Sunny, Sunny, Moon]
</script>

Custom Colors ​

Use the colors attribute to customize colors for different levels:

vue
<template>
  <div>
    <h4>Custom colors</h4>
    <el-rate
      v-model="value1"
      :colors="customColors"
    />
    <p>Rating: {{ value1 }}</p>
    
    <h4>Gradient color rating</h4>
    <el-rate
      v-model="value2"
      :colors="gradientColors"
      allow-half
    />
    <p>Rating: {{ value2 }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const value1 = ref(4)
const value2 = ref(3.5)

const customColors = {
  2: '#99A9BF',
  4: '#F7BA2A', 
  5: '#FF9900'
}

const gradientColors = [
  '#ff4d4f',
  '#ff7a45', 
  '#ffa940',
  '#ffec3d',
  '#52c41a'
]
</script>

Sizes ​

Use the size attribute to set the size of the rating:

vue
<template>
  <div>
    <h4>Large size</h4>
    <el-rate v-model="value1" size="large" />
    
    <h4>Default size</h4>
    <el-rate v-model="value2" />
    
    <h4>Small size</h4>
    <el-rate v-model="value3" size="small" />
  </div>
</template>

<script setup>
import { ref } from 'vue'

const value1 = ref(4)
const value2 = ref(4)
const value3 = ref(4)
</script>

Practical Application Examples ​

Product Review Component ​

vue
<template>
  <div class="product-review">
    <h3>Product Review</h3>
    
    <div class="review-form">
      <div class="review-item">
        <label>Product Quality:</label>
        <el-rate
          v-model="review.quality"
          :texts="qualityTexts"
          show-text
          @change="handleRateChange('quality', $event)"
        />
      </div>
      
      <div class="review-item">
        <label>Shipping Speed:</label>
        <el-rate
          v-model="review.delivery"
          :texts="deliveryTexts"
          show-text
          @change="handleRateChange('delivery', $event)"
        />
      </div>
      
      <div class="review-item">
        <label>Customer Service:</label>
        <el-rate
          v-model="review.service"
          :texts="serviceTexts"
          show-text
          @change="handleRateChange('service', $event)"
        />
      </div>
      
      <div class="review-item">
        <label>Overall Rating:</label>
        <el-rate
          v-model="review.overall"
          allow-half
          show-score
          readonly
          :colors="['#ff4d4f', '#ffa940', '#52c41a']"
        />
      </div>
      
      <div class="review-actions">
        <el-button type="primary" @click="submitReview">Submit Review</el-button>
        <el-button @click="resetReview">Reset</el-button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { reactive, computed } from 'vue'
import { ElMessage } from 'element-plus'

const review = reactive({
  quality: 0,
  delivery: 0,
  service: 0,
  overall: 0
})

const qualityTexts = ['Poor', 'Fair', 'Average', 'Good', 'Excellent']
const deliveryTexts = ['Very Slow', 'Slow', 'Average', 'Fast', 'Very Fast']
const serviceTexts = ['Poor', 'Fair', 'Average', 'Good', 'Excellent']

const handleRateChange = (type, value) => {
  // Calculate overall rating
  const total = review.quality + review.delivery + review.service
  const count = [review.quality, review.delivery, review.service].filter(v => v > 0).length
  review.overall = count > 0 ? Number((total / count).toFixed(1)) : 0
  
  ElMessage.success(`${type} rating updated: ${value} stars`)
}

const submitReview = () => {
  if (review.quality === 0 || review.delivery === 0 || review.service === 0) {
    ElMessage.warning('Please complete all rating items')
    return
  }
  
  ElMessage.success('Review submitted successfully!')
  console.log('Review data:', review)
}

const resetReview = () => {
  review.quality = 0
  review.delivery = 0
  review.service = 0
  review.overall = 0
  ElMessage.info('Ratings have been reset')
}
</script>

<style scoped>
.product-review {
  max-width: 500px;
  padding: 20px;
  border: 1px solid #dcdfe6;
  border-radius: 8px;
}

.review-item {
  display: flex;
  align-items: center;
  margin-bottom: 16px;
}

.review-item label {
  width: 120px;
  margin-right: 12px;
  font-weight: 500;
}

.review-actions {
  margin-top: 20px;
  text-align: center;
}

.review-actions .el-button {
  margin: 0 8px;
}
</style>

User Feedback Rating ​

vue
<template>
  <div class="feedback-rating">
    <h3>User Experience Feedback</h3>
    
    <div class="feedback-list">
      <div v-for="item in feedbackItems" :key="item.id" class="feedback-item">
        <div class="feedback-info">
          <h4>{{ item.title }}</h4>
          <p>{{ item.description }}</p>
        </div>
        <div class="feedback-rating-control">
          <el-rate
            v-model="item.rating"
            :icons="item.icons"
            :colors="item.colors"
            :allow-half="item.allowHalf"
            :show-text="item.showText"
            :texts="item.texts"
            @change="handleFeedbackChange(item)"
          />
        </div>
      </div>
    </div>
    
    <div class="feedback-summary">
      <h4>Overall Satisfaction</h4>
      <el-rate
        v-model="overallSatisfaction"
        :max="10"
        allow-half
        show-score
        score-template="{value}/10 points"
        readonly
        :colors="['#ff4d4f', '#ffa940', '#52c41a']"
      />
    </div>
  </div>
</template>

<script setup>
import { ref, reactive, computed } from 'vue'
import { ElMessage } from 'element-plus'
import { Star, StarFilled, Sunny } from '@element-plus/icons-vue'

const feedbackItems = reactive([
  {
    id: 1,
    title: 'Interface Design',
    description: 'Are you satisfied with our interface design?',
    rating: 0,
    icons: [Star, Star, StarFilled],
    colors: ['#99A9BF', '#F7BA2A', '#FF9900'],
    allowHalf: true,
    showText: true,
    texts: ['Poor', 'Fair', 'Average', 'Good', 'Excellent']
  },
  {
    id: 2,
    title: 'Feature Completeness',
    description: 'Do our features meet your needs?',
    rating: 0,
    icons: [Star, Star, StarFilled],
    colors: ['#99A9BF', '#F7BA2A', '#FF9900'],
    allowHalf: true,
    showText: true,
    texts: ['Poor', 'Fair', 'Average', 'Good', 'Excellent']
  },
  {
    id: 3,
    title: 'User Experience',
    description: 'How is the overall user experience?',
    rating: 0,
    icons: [Sunny, Sunny, Sunny],
    colors: ['#ff4d4f', '#ffa940', '#52c41a'],
    allowHalf: false,
    showText: true,
    texts: ['Poor', 'Fair', 'Average', 'Good', 'Excellent']
  }
])

const overallSatisfaction = computed(() => {
  const total = feedbackItems.reduce((sum, item) => sum + item.rating, 0)
  const count = feedbackItems.filter(item => item.rating > 0).length
  return count > 0 ? Number(((total / count) * 2).toFixed(1)) : 0
})

const handleFeedbackChange = (item) => {
  ElMessage.success(`${item.title} rating updated: ${item.rating} stars`)
}
</script>

<style scoped>
.feedback-rating {
  max-width: 600px;
  padding: 20px;
  border: 1px solid #dcdfe6;
  border-radius: 8px;
}

.feedback-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 0;
  border-bottom: 1px solid #f0f0f0;
}

.feedback-item:last-child {
  border-bottom: none;
}

.feedback-info h4 {
  margin: 0 0 4px 0;
  font-size: 16px;
  color: #303133;
}

.feedback-info p {
  margin: 0;
  font-size: 14px;
  color: #606266;
}

.feedback-summary {
  margin-top: 20px;
  padding-top: 20px;
  border-top: 2px solid #e4e7ed;
  text-align: center;
}

.feedback-summary h4 {
  margin-bottom: 12px;
  color: #303133;
}
</style>

API Documentation ​

Rate Attributes ​

NameDescriptionTypeDefault
model-value / v-modelbinding valuenumber0
maxmaximum scorenumber5
disabledwhether Rate is disabledbooleanfalse
readonlywhether Rate is read-onlybooleanfalse
allow-halfwhether picking half start is allowedbooleanfalse
low-thresholdthreshold value between low and medium level. The value itself will be included in low levelnumber2
high-thresholdthreshold value between medium and high level. The value itself will be included in high levelnumber4
colorscolors for icons. If array, it should have 3 elements, each of which corresponds with a score level, else if object, the key should be threshold value between two levels, and the value should be corresponding colorobject / array['#F7BA2A', '#F7BA2A', '#F7BA2A']
void-colorcolor of unselected iconsstring#C6D1DE
disabled-void-colorcolor of unselected read-only iconsstring#EFF2F7
iconsicon components. If array, it should have 3 elements, each of which corresponds with a score level, else if object, the key should be threshold value between two levels, and the value should be corresponding icon componentobject / array[StarFilled, StarFilled, StarFilled]
void-iconcomponent of unselected iconsstring / ComponentStar
disabled-void-iconcomponent of unselected read-only iconsstring / ComponentStarFilled
show-textwhether to display textsbooleanfalse
show-scorewhether to display current score. show-score and show-text cannot be true at the same timebooleanfalse
text-colorcolor of textsstring#1F2D3D
textstext arrayarray['Extremely bad', 'Disappointed', 'Fair', 'Satisfied', 'Surprise']
score-templatescore templatestring
sizesize of Rateenum—
labelscreen reader labelstring—
idnative id attributestring—

Rate Events ​

NameDescriptionType
changetriggers when the value changesFunction

Rate Exposes ​

NameDescriptionType
setCurrentValueset current valueFunction
resetCurrentValuereset current valueFunction

Practice Exercises ​

Exercise 1: Multi-dimensional Rating System ​

Create a multi-dimensional rating system:

vue
<template>
  <div class="multi-dimension-rating">
    <h3>Course Evaluation</h3>
    <div v-for="dimension in dimensions" :key="dimension.key" class="dimension-item">
      <label>{{ dimension.label }}:</label>
      <el-rate
        v-model="dimension.value"
        :allow-half="dimension.allowHalf"
        :show-text="dimension.showText"
        :texts="dimension.texts"
        @change="updateOverallRating"
      />
    </div>
    
    <div class="overall-rating">
      <label>Overall Rating:</label>
      <el-rate
        v-model="overallRating"
        allow-half
        show-score
        readonly
        :colors="['#ff4d4f', '#ffa940', '#52c41a']"
      />
    </div>
  </div>
</template>

<script setup>
import { reactive, ref } from 'vue'

const dimensions = reactive([
  {
    key: 'content',
    label: 'Content Quality',
    value: 0,
    allowHalf: true,
    showText: true,
    texts: ['Poor', 'Fair', 'Average', 'Good', 'Excellent']
  },
  {
    key: 'teacher',
    label: 'Instructor Level',
    value: 0,
    allowHalf: true,
    showText: true,
    texts: ['Poor', 'Fair', 'Average', 'Good', 'Excellent']
  },
  {
    key: 'difficulty',
    label: 'Appropriate Difficulty',
    value: 0,
    allowHalf: true,
    showText: true,
    texts: ['Very Hard', 'Hard', 'Moderate', 'Easy', 'Very Easy']
  }
])

const overallRating = ref(0)

const updateOverallRating = () => {
  const total = dimensions.reduce((sum, dim) => sum + dim.value, 0)
  const count = dimensions.filter(dim => dim.value > 0).length
  overallRating.value = count > 0 ? Number((total / count).toFixed(1)) : 0
}
</script>

Exercise 2: Dynamic Rating Display ​

Create a dynamic rating display component:

vue
<template>
  <div class="dynamic-rating-display">
    <h3>User Rating Statistics</h3>
    <div v-for="rating in ratingStats" :key="rating.stars" class="rating-row">
      <span class="stars">{{ rating.stars }} stars</span>
      <el-rate
        :model-value="rating.stars"
        readonly
        :max="5"
      />
      <div class="progress-bar">
        <div 
          class="progress-fill"
          :style="{ width: rating.percentage + '%' }"
        ></div>
      </div>
      <span class="count">{{ rating.count }} users</span>
    </div>
    
    <div class="average-rating">
      <span>Average Rating:</span>
      <el-rate
        :model-value="averageRating"
        allow-half
        readonly
        show-score
        :colors="['#ff4d4f', '#ffa940', '#52c41a']"
      />
    </div>
  </div>
</template>

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

const ratingStats = [
  { stars: 5, count: 120 },
  { stars: 4, count: 80 },
  { stars: 3, count: 30 },
  { stars: 2, count: 10 },
  { stars: 1, count: 5 }
]

const totalCount = computed(() => {
  return ratingStats.reduce((sum, rating) => sum + rating.count, 0)
})

const averageRating = computed(() => {
  const totalScore = ratingStats.reduce((sum, rating) => {
    return sum + (rating.stars * rating.count)
  }, 0)
  return Number((totalScore / totalCount.value).toFixed(1))
})

// Calculate percentages
ratingStats.forEach(rating => {
  rating.percentage = (rating.count / totalCount.value * 100).toFixed(1)
})
</script>

Common Issues ​

1. Rating Value Not Updating ​

Issue: Rating value is not correctly bound or updated

Solution:

vue
<!-- Ensure correct v-model usage -->
<el-rate v-model="ratingValue" />

<!-- Ensure initial value is a number type -->
<script setup>
const ratingValue = ref(0) // not ref('0')
</script>

2. Custom Icons Not Displaying ​

Issue: Custom icons are not displaying correctly

Solution:

vue
<template>
  <el-rate
    v-model="value"
    :icons="[Star, Star, StarFilled]"
    :void-icon="ChatDotRound"
  />
</template>

<script setup>
import { Star, StarFilled, ChatDotRound } from '@element-plus/icons-vue'
</script>

3. Half-Star Rating Precision Issues ​

Issue: Precision control for half-star ratings

Solution:

vue
<el-rate
  v-model="value"
  allow-half
  @change="handleRateChange"
/>

<script setup>
const handleRateChange = (value) => {
  // Ensure precision of 0.5
  const roundedValue = Math.round(value * 2) / 2
  console.log('Rating:', roundedValue)
}
</script>

Best Practices ​

  1. Semantic Labels: Provide meaningful labels for rating components
  2. User Feedback: Provide appropriate feedback when ratings change
  3. Data Validation: Ensure the validity of rating data
  4. Accessibility: Ensure keyboard navigation and screen reader support
  5. Visual Consistency: Maintain consistent rating styles throughout an application
  6. Reasonable Defaults: Set reasonable default configurations for rating components

Summary ​

The Rate component is a feature-rich evaluation component that supports:

  • Basic rating functionality
  • Multiple states (disabled, read-only)
  • Half-star ratings
  • Custom icons and colors
  • Auxiliary text and score display
  • Size control
  • Rich configuration options
  • Good accessibility support

Mastering the Rate component can help you build more intuitive and user-friendly evaluation systems.

References ​

Element Plus Study Guide