Skip to content

UIRating

UIRating

A versatile rating component that allows users to view and input ratings using stars or custom icons, with support for half-stars and custom styling.

<template>
<UIRating
v-model="rating"
:max="5"
:precision="0.5"
:readonly="false"
:size="24"
:hover-text="hoverLabels"
@change="handleRatingChange"
>
<template #icon="{ filled, hovered }">
<StarIcon
:class="{
'text-yellow-400': filled,
'text-gray-300': !filled,
'text-yellow-300': !filled && hovered
}"
/>
</template>
</UIRating>
</template>
<script setup lang="ts">
import { StarIcon } from '@gohighlevel/ghl-icons/24/solid'
const rating = ref(3.5)
const hoverLabels = ['Poor', 'Fair', 'Good', 'Very Good', 'Excellent']
const handleRatingChange = (value: number) => {
console.log('New rating:', value)
}
</script>

Props

  • modelValue (number): Current rating value
  • max (number): Maximum rating value (default: 5)
  • precision (number): Rating precision (0.5 or 1)
  • readonly (boolean): Prevent rating changes
  • disabled (boolean): Disable rating interaction
  • size (number): Icon size in pixels
  • color (string): Rating color
  • inactiveColor (string): Inactive star color
  • hoverColor (string): Hover state color
  • hoverText (array): Labels for hover states
  • showValue (boolean): Display numeric value
  • clearable (boolean): Allow clearing rating
  • required (boolean): Mark as required field

Events

  • update:modelValue: Emitted when rating changes
  • change: Emitted after rating change
  • hover: Emitted on hover state change
  • focus: Emitted on focus
  • blur: Emitted on blur

Slots

  • icon: Custom icon template
  • value: Custom value display
  • label: Custom label content
  • before: Content before rating
  • after: Content after rating

Usage Examples

  1. Basic Rating Display:
<template>
<UIRating
:model-value="4.5"
:readonly="true"
color="text-yellow-400"
/>
</template>
  1. Interactive Rating with Half Stars:
<template>
<div class="space-y-2">
<label class="text-sm font-medium">
Rate your experience
</label>
<UIRating
v-model="userRating"
:precision="0.5"
:hover-text="ratingLabels"
class="text-2xl"
>
<template #after="{ hoverText }">
<span class="ml-2 text-sm text-gray-600">
{{ hoverText || displayRating }}
</span>
</template>
</UIRating>
</div>
</template>
<script setup>
const userRating = ref(0)
const ratingLabels = [
'Terrible',
'Poor',
'Average',
'Good',
'Excellent'
]
const displayRating = computed(() =>
userRating.value ? ratingLabels[Math.ceil(userRating.value) - 1] : ''
)
</script>
  1. Custom Icons and Styling:
<template>
<UIRating
v-model="satisfaction"
:max="3"
:precision="1"
>
<template #icon="{ filled, hovered }">
<div class="p-1">
<EmojiIcon
:name="getEmojiIcon(filled)"
:class="{
'text-3xl transform transition-transform': true,
'scale-110': hovered,
'text-gray-300': !filled,
'text-green-500': filled
}"
/>
</div>
</template>
</UIRating>
</template>
<script setup>
const satisfaction = ref(0)
const getEmojiIcon = (filled: boolean) => {
if (!filled) return 'emoji-neutral'
switch (satisfaction.value) {
case 1: return 'emoji-sad'
case 2: return 'emoji-neutral'
case 3: return 'emoji-happy'
default: return 'emoji-neutral'
}
}
</script>

Best Practices

  1. Visual Feedback:

    • Clear active states
    • Smooth transitions
    • Consistent sizing
    • Appropriate spacing
  2. User Experience:

    • Intuitive interaction
    • Clear value display
    • Hover feedback
    • Touch support
  3. Accessibility:

    • Keyboard navigation
    • Screen reader support
    • Clear labels
    • Focus indicators
  4. Validation:

    • Required field handling
    • Error states
    • Clear feedback
    • Form integration

Common Use Cases

  1. Product Reviews:
<template>
<div class="review-form space-y-4">
<div class="flex items-center space-x-4">
<span class="font-medium">Overall Rating</span>
<UIRating
v-model="review.rating"
:required="true"
:precision="0.5"
/>
</div>
<div class="grid grid-cols-2 gap-4">
<div v-for="aspect in aspects" :key="aspect.id">
<div class="text-sm">{{ aspect.label }}</div>
<UIRating
v-model="review.aspects[aspect.id]"
:size="16"
/>
</div>
</div>
<UITextarea
v-model="review.comment"
placeholder="Write your review..."
/>
<UIButton
type="primary"
:disabled="!isValid"
@click="submitReview"
>
Submit Review
</UIButton>
</div>
</template>
  1. Feedback Collection:
<template>
<div class="feedback-widget">
<h3 class="text-lg font-medium">
How helpful was this article?
</h3>
<UIRating
v-model="helpfulRating"
:max="5"
:hover-text="helpfulnessLabels"
class="my-4"
>
<template #after="{ hoverText }">
<span class="ml-2 text-sm text-gray-600">
{{ hoverText }}
</span>
</template>
</UIRating>
<div v-if="helpfulRating" class="mt-4">
<UITextarea
v-model="feedbackComment"
placeholder="Tell us more about your experience..."
rows="3"
/>
</div>
</div>
</template>
  1. Performance Metrics:
<template>
<div class="performance-review">
<div
v-for="metric in metrics"
:key="metric.id"
class="flex items-center justify-between py-2"
>
<div class="w-1/3">
<div class="font-medium">{{ metric.label }}</div>
<div class="text-sm text-gray-500">
{{ metric.description }}
</div>
</div>
<UIRating
v-model="ratings[metric.id]"
:readonly="isReadonly"
:precision="0.5"
:hover-text="ratingDescriptions"
>
<template #after="{ modelValue }">
<span class="ml-2 tabular-nums">
{{ modelValue.toFixed(1) }}
</span>
</template>
</UIRating>
</div>
<div class="mt-4 pt-4 border-t">
<div class="flex items-center justify-between">
<span class="font-medium">Overall Score</span>
<span class="text-lg font-semibold">
{{ averageRating.toFixed(1) }}
</span>
</div>
</div>
</div>
</template>