FluxUI Pro is live - modern UI, powerful animations, zero hassle.
Components
Rating

Rating

Interactive star rating component with hover effects and customizable styling.

Installation

1

Install the packages

npm i motion clsx tailwind-merge
2

Add util file

lib/util.ts
import { ClassValue, clsx } from "clsx"; import { twMerge } from "tailwind-merge"; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); }
3

Copy and paste the following code into your project

rating.tsx
"use client"; import { cn } from "@/lib/utils"; import { motion } from "motion/react"; import React, { useState } from "react"; import { FiStar } from "react-icons/fi"; interface RatingProps { value?: number; onChange?: (value: number) => void; max?: number; size?: "sm" | "md" | "lg"; readonly?: boolean; showValue?: boolean; } const Rating: React.FC<RatingProps> = ({ value = 0, onChange = () => {}, max = 5, size = "md", readonly = false, showValue = false }) => { const [hoverValue, setHoverValue] = useState(0); const sizeClasses = { sm: "h-4 w-4", md: "h-5 w-5", lg: "h-6 w-6", }; const handleClick = (rating: number) => { if (!readonly) { onChange(rating); } }; const handleMouseEnter = (rating: number) => { if (!readonly) { setHoverValue(rating); } }; const handleMouseLeave = () => { if (!readonly) { setHoverValue(0); } }; const displayValue = hoverValue || value; return ( <div className="flex flex-col items-center gap-4"> <div className="flex items-center gap-1"> {Array.from({ length: max }).map((_, index) => { const rating = index + 1; const isFilled = rating <= displayValue; return ( <motion.button key={index} onClick={() => handleClick(rating)} onMouseEnter={() => handleMouseEnter(rating)} onMouseLeave={handleMouseLeave} className={cn( "transition-colors", readonly ? "cursor-default" : "cursor-pointer hover:scale-110" )} whileHover={!readonly ? { scale: 1.1 } : {}} whileTap={!readonly ? { scale: 0.9 } : {}} > <FiStar className={cn( sizeClasses[size], isFilled ? "fill-yellow-400 text-yellow-400" : "text-neutral-400 hover:text-yellow-400" )} /> </motion.button> ); })} </div> {showValue && ( <motion.div className="text-sm text-neutral-400" key={displayValue} initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.2 }} > {displayValue} out of {max} stars </motion.div> )} </div> ); }; export default Rating;
4

Update the import paths to match your project setup

Props

PropTypeDefaultDescription
valuenumber0Current rating value.
onChangefunction() => {}Callback when rating changes.
maxnumber5Maximum rating value.
sizestringmdSize of the stars (sm, md, lg).
readonlybooleanfalseMake the rating read-only.
showValuebooleanfalseShow the rating value text.