Rating
A component that allows users to rate an item with stars.
<!-- Rating -->
<!-- An Alpine.js and Tailwind CSS component by https://pinemix.com -->
<div
class="flex flex-col items-center justify-center gap-2 rounded-lg border-2 border-dashed border-zinc-200/75 py-44 text-zinc-800 dark:border-zinc-700 dark:text-zinc-200"
>
<div
x-data="{
rating: 0,
iconFeedback: true,
// Helpers
ratings: [1, 2, 3, 4, 5],
hoverRating: 0,
rated: false,
ratedTimeout: null,
// Rate the component
rate(rating) {
this.rated = true;
this.rating = rating;
// Clear any existing timeout
if (this.ratedTimeout) {
clearTimeout(this.ratedTimeout);
}
this.ratedTimeout = setTimeout(() => {
this.rated = false;
}, 1500);
}
}"
>
<!-- Rating Stars -->
<div
class="relative inline-flex items-center rounded-xl border bg-white px-2 py-1 transition-all duration-200 ease-out dark:bg-zinc-950/50"
x-bind:class="{
'border-emerald-300 dark:border-emerald-700': rated && rating > 2,
'border-rose-300 dark:border-rose-700': rated && rating < 3,
'border-zinc-200/75 dark:border-zinc-800': !rated
}"
>
<!-- Icon Feedback -->
<div
x-show="rated && iconFeedback"
x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="opacity-0 scale-90 translate-y-0 rotate-45 scale-50"
x-transition:enter-end="opacity-100 scale-100 -translate-y-14 rotate-0 scale-105"
x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100 scale-100 -translate-y-14 rotate-0 scale-105"
x-transition:leave-end="opacity-0 scale-90 translate-y-0 rotate-45 scale-50"
class="absolute inset-0 flex -translate-y-14 scale-105 rotate-0 items-center justify-center"
>
<div
class="flex items-center justify-center rounded-full border p-2 ring-3"
x-bind:class="{
'border-emerald-300/75 bg-emerald-200/50 ring-emerald-200/20 dark:border-emerald-700/75 dark:bg-emerald-700/50 dark:ring-emerald-700/20': rating > 2,
'border-rose-300/75 bg-rose-200/50 ring-rose-200/20 dark:border-rose-700/75 dark:bg-rose-700/50 dark:ring-rose-700/20': rating < 3
}"
>
<svg
x-show="rating > 2"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="hi-solid hi-hand-thumb-up inline-block size-6 text-emerald-600 dark:text-emerald-400"
>
<path
d="M7.493 18.5c-.425 0-.82-.236-.975-.632A7.48 7.48 0 0 1 6 15.125c0-1.75.599-3.358 1.602-4.634.151-.192.373-.309.6-.397.473-.183.89-.514 1.212-.924a9.042 9.042 0 0 1 2.861-2.4c.723-.384 1.35-.956 1.653-1.715a4.498 4.498 0 0 0 .322-1.672V2.75A.75.75 0 0 1 15 2a2.25 2.25 0 0 1 2.25 2.25c0 1.152-.26 2.243-.723 3.218-.266.558.107 1.282.725 1.282h3.126c1.026 0 1.945.694 2.054 1.715.045.422.068.85.068 1.285a11.95 11.95 0 0 1-2.649 7.521c-.388.482-.987.729-1.605.729H14.23c-.483 0-.964-.078-1.423-.23l-3.114-1.04a4.501 4.501 0 0 0-1.423-.23h-.777ZM2.331 10.727a11.969 11.969 0 0 0-.831 4.398 12 12 0 0 0 .52 3.507C2.28 19.482 3.105 20 3.994 20H4.9c.445 0 .72-.498.523-.898a8.963 8.963 0 0 1-.924-3.977c0-1.708.476-3.305 1.302-4.666.245-.403-.028-.959-.5-.959H4.25c-.832 0-1.612.453-1.918 1.227Z"
/>
</svg>
<svg
x-show="rating < 3"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="hi-solid hi-hand-thumb-down inline-block size-6 text-rose-600 dark:text-rose-400"
>
<path
d="M15.73 5.5h1.035A7.465 7.465 0 0 1 18 9.625a7.465 7.465 0 0 1-1.235 4.125h-.148c-.806 0-1.534.446-2.031 1.08a9.04 9.04 0 0 1-2.861 2.4c-.723.384-1.35.956-1.653 1.715a4.499 4.499 0 0 0-.322 1.672v.633A.75.75 0 0 1 9 22a2.25 2.25 0 0 1-2.25-2.25c0-1.152.26-2.243.723-3.218.266-.558-.107-1.282-.725-1.282H3.622c-1.026 0-1.945-.694-2.054-1.715A12.137 12.137 0 0 1 1.5 12.25c0-2.848.992-5.464 2.649-7.521C4.537 4.247 5.136 4 5.754 4H9.77a4.5 4.5 0 0 1 1.423.23l3.114 1.04a4.5 4.5 0 0 0 1.423.23ZM21.669 14.023c.536-1.362.831-2.845.831-4.398 0-1.22-.182-2.398-.52-3.507-.26-.85-1.084-1.368-1.973-1.368H19.1c-.445 0-.72.498-.523.898.591 1.2.924 2.55.924 3.977a8.958 8.958 0 0 1-1.302 4.666c-.245.403.028.959.5.959h1.053c.832 0 1.612-.453 1.918-1.227Z"
/>
</svg>
</div>
</div>
<!-- END Icon Feedback -->
<!-- Stars -->
<div class="relative">
<template x-for="(star, index) in ratings" :key="index">
<button
x-on:click="rate(star)"
x-on:mouseenter="hoverRating = star"
x-on:mouseleave="hoverRating = 0"
x-bind:aria-label="`Rate ${star} out of 5 stars`"
type="button"
class="rounded p-1 transition hover:scale-110 focus:outline-none focus-visible:ring-2 focus-visible:ring-teal-500 focus-visible:ring-offset-2 active:scale-100"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="hi-solid hi-star inline-block size-6 transition-colors duration-150"
x-bind:class="{
'text-orange-500 dark:text-orange-400': hoverRating >= star || rating >= star,
'text-zinc-300 dark:text-zinc-700': hoverRating < star && rating < star
}"
>
<path
fill-rule="evenodd"
d="M10.788 3.21c.448-1.077 1.976-1.077 2.424 0l2.082 5.006 5.404.434c1.164.093 1.636 1.545.749 2.305l-4.117 3.527 1.257 5.273c.271 1.136-.964 2.033-1.96 1.425L12 18.354 7.373 21.18c-.996.608-2.231-.29-1.96-1.425l1.257-5.273-4.117-3.527c-.887-.76-.415-2.212.749-2.305l5.404-.434 2.082-5.005Z"
clip-rule="evenodd"
/>
</svg>
</button>
</template>
</div>
<!-- END Stars -->
</div>
<!-- END Rating Stars -->
<!-- Feedback -->
<div class="mt-2 text-center text-sm font-medium">
<span x-text="hoverRating || rating" class="font-bold"></span>/5 stars
</div>
<!-- END Feedback -->
</div>
</div>
<!-- END Rating -->
Props
The available data properties for this component.
Property | Default | Description |
---|---|---|
rating | 0 | The current rating value |
iconFeedback | true | Sets the icon feedback functionality |
Designed with
Tailkit
Featuring 1,900+ Tailwind CSS code snippets for HTML, React, Vue.js and Alpine.js projects
Unlock 15+ free templates
Join our pixelcave newsletter to get them now & we'll also keep you updated about any new Pinemix components!