shadcn.io is not affiliated with official shadcn/ui
Shadcn Rating for React and Tailwind
Show reviews and ratings in a visual format.
VVVinicius Vicentini
Tuestday morning at Mercado N.89
Rate your driver
Installation
bunx --bun shadcn@latest add https://kit.dev/r/rating.jsonpnpm dlx shadcn@latest add https://kit.dev/r/rating.jsonnpx shadcn@latest add https://kit.dev/r/rating.jsonyarn shadcn@latest add https://kit.dev/r/rating.jsonInstall the dependencies:
bun add @ark-ui/react lucide-reactpnpm add @ark-ui/react lucide-reactnpm install @ark-ui/react lucide-reactyarn add @ark-ui/react lucide-reactImport the following variables into your CSS file
@theme inline {
--color-destructive-foreground: var(--destructive-foreground);
--color-info: var(--info);
--color-info-foreground: var(--info-foreground);
--color-success: var(--success);
--color-success-foreground: var(--success-foreground);
--color-warning: var(--warning);
--color-warning-foreground: var(--warning-foreground);
}
:root {
--destructive-foreground: var(--color-red-700);
--info: var(--color-blue-500);
--info-foreground: var(--color-blue-700);
--success: var(--color-emerald-500);
--success-foreground: var(--color-emerald-700);
--warning: var(--color-amber-500);
--warning-foreground: var(--color-amber-700);
}
.dark {
--destructive-foreground: var(--color-red-400);
--info: var(--color-blue-500);
--info-foreground: var(--color-blue-400);
--success: var(--color-emerald-500);
--success-foreground: var(--color-emerald-400);
--warning: var(--color-amber-500);
--warning-foreground: var(--color-amber-400);
}Copy and paste the following code into your project.
"use client";
import {
RatingGroup as ArkRatingGroup,
useRatingGroupContext,
} from "@ark-ui/react/rating-group";
import { StarIcon } from "lucide-react";
import React from "react";
import { cn } from "@/lib/utils";
export const useRating = useRatingGroupContext;
interface RatingProps extends React.ComponentProps<typeof ArkRatingGroup.Root> {
/**
* The icon to use for the rating.
*
* @default <StarIcon />
*/
icon?: React.ReactNode;
}
export const Rating = (props: RatingProps) => {
const {
icon = <StarIcon />,
allowHalf = false,
count = 5,
className,
...rest
} = props;
return (
<ArkRatingGroup.Root
allowHalf={allowHalf}
className={cn(
"**:data-[slot=rating-item-indicator]:size-6",
"text-warning",
"data-readonly:pointer-events-none",
className
)}
count={count}
data-slot="rating"
{...rest}
>
<ArkRatingGroup.Control
className="inline-flex items-center gap-1"
data-slot="rating-control"
>
<ArkRatingGroup.Context>
{({ items }) =>
items.map((item) => (
<RatingItem index={item} key={item}>
<ArkRatingGroup.ItemContext>
{({ half, highlighted }) => (
<span
className={cn(
"relative inline-flex",
"**:data-fg:text-current **:data-fg:[clip-path:inset(0_0_0_0)]",
"[&[data-half]_[data-fg]]:[clip-path:inset(0_50%_0_0)]",
"[&:not([data-highlighted])_[data-fg]]:[clip-path:inset(0_100%_0_0)]",
"[&_svg]:absolute [&_svg]:inset-0 [&_svg]:size-full [&_svg]:text-current"
)}
data-half={half ? "" : undefined}
data-highlighted={highlighted ? "" : undefined}
data-slot="rating-item-indicator"
>
{React.cloneElement(
icon as React.ReactElement,
{
"data-bg": "",
} as React.ComponentProps<"svg">
)}
{React.cloneElement(
icon as React.ReactElement,
{
"data-fg": "",
fill: "currentColor",
} as React.ComponentProps<"svg">
)}
</span>
)}
</ArkRatingGroup.ItemContext>
</RatingItem>
))
}
</ArkRatingGroup.Context>
<ArkRatingGroup.HiddenInput />
</ArkRatingGroup.Control>
</ArkRatingGroup.Root>
);
};
export const RatingItem = (
props: React.ComponentProps<typeof ArkRatingGroup.Item>
) => {
const { className, ...rest } = props;
return (
<ArkRatingGroup.Item
className={cn(
"inline-flex items-center justify-center",
"rounded-md",
"not-[[data-disabled],[data-readonly]]:cursor-pointer",
"data-disabled:opacity-64 data-disabled:grayscale",
"outline-none focus-visible:ring-current not-data-readonly:focus-visible:ring-[3px] focus-visible:ring-offset-1 focus-visible:ring-offset-background",
className
)}
data-slot="rating-item"
{...rest}
/>
);
};Update the import paths to match your project setup.
Usage
import { RatingGroup } from "@/components/ui/rating";<RatingGroup />Controlled
Use value and onValueChange to control the rating programmatically.
States
Readonly
Use the readOnly prop to display a rating without interaction.
Disabled
Use the disabled prop to prevent interaction and show a disabled state.
Examples
Half star
Use allowHalf to allow half-star selections.
Count
Use the count prop to show more or less stars.
Testimonial
Display a read-only rating inside a testimonial card.
Customize size
Use the className prop to set the size of the rating.
Custom icon
Compose the rating with a different icon.
Custom color
Override the filled color with className.
API Reference
Rating
Root component.
| Prop | Type | Default |
|---|---|---|
allowHalf | boolean | false |
count | number | 5 |
defaultValue | number | - |
value | number | - |
onValueChange | (details: ValueChangeDetails) => void | - |
readOnly | boolean | - |
disabled | boolean | - |
className | string | - |
For a complete list of props, see the Ark UI documentation.