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 valuemax(number): Maximum rating value (default: 5)precision(number): Rating precision (0.5 or 1)readonly(boolean): Prevent rating changesdisabled(boolean): Disable rating interactionsize(number): Icon size in pixelscolor(string): Rating colorinactiveColor(string): Inactive star colorhoverColor(string): Hover state colorhoverText(array): Labels for hover statesshowValue(boolean): Display numeric valueclearable(boolean): Allow clearing ratingrequired(boolean): Mark as required field
Events
update:modelValue: Emitted when rating changeschange: Emitted after rating changehover: Emitted on hover state changefocus: Emitted on focusblur: Emitted on blur
Slots
icon: Custom icon templatevalue: Custom value displaylabel: Custom label contentbefore: Content before ratingafter: Content after rating
Usage Examples
- Basic Rating Display:
<template> <UIRating :model-value="4.5" :readonly="true" color="text-yellow-400" /></template>- 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>- 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
-
Visual Feedback:
- Clear active states
- Smooth transitions
- Consistent sizing
- Appropriate spacing
-
User Experience:
- Intuitive interaction
- Clear value display
- Hover feedback
- Touch support
-
Accessibility:
- Keyboard navigation
- Screen reader support
- Clear labels
- Focus indicators
-
Validation:
- Required field handling
- Error states
- Clear feedback
- Form integration
Common Use Cases
- 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>- 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>- 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>