implement
Rating Group

Rating Group

A row of stars for scoring something.

3 out of 5
import { Div, signal, Span } from "@implementjs/core";
import { RatingGroup, RatingGroupItem } from "@/lib/components/ui/rating-group";

export default function RatingGroupDemo() {
	const value = signal(3);

	return Div(
		{ class: "flex flex-col items-center gap-2" },
		RatingGroup(
			{ value, "aria-label": "Rate this library" },
			...Array.from({ length: 5 }, (_, index) => RatingGroupItem({ index })),
		),
		Span(
			{ class: "text-sm text-muted-foreground tabular-nums" },
			value.bind((v) => `${v} out of 5`),
		),
	);
}

Installation

npx jsrepo add @implementjs/ui/rating-group

It installs @implementjs/lucide at the same time.

Usage

Each item renders a star that fills while it is active — pass children to use a different mark. The items are indexed rather than valued, so a five-star rating is Array.from({ length: 5 }).

import { signal } from "@implementjs/core";
import { RatingGroup, RatingGroupItem } from "@/lib/components/ui/rating-group";

const value = signal(3);

RatingGroup(
	{ value, "aria-label": "Rate this library" },
	...Array.from({ length: 5 }, (_, index) => RatingGroupItem({ index })),
);

Read-only

readonly on the root shows a score without offering to change it — the cursor stays an arrow and the items stop responding, but the value is still announced:

RatingGroup({ value: 4, readonly: true, "aria-label": "Average rating" } /* items */);

API Reference

Every prop the styling does not consume is forwarded to the Rating Group primitive, so the tables below are the whole surface — the behavior props and the styling ones together.

RatingGroup

The root and the single focusable control. Announces as a slider: role="slider" with the aria value attributes. Renders a Div; extra props are forwarded onto it.

PropTypeDefaultDescription
valueSignal<number> | number0The current rating. Pass a signal to control it from outside; a number seeds uncontrolled state.
minnumber0The lowest value the rating can take.
maxnumber5The highest value the rating can take.
allowHalfbooleanfalseWork in half steps: pointer position picks the half, arrows move by 0.5.
readonlybooleanfalseThe value can be read but not changed.
disabledSignal<boolean> | booleanfalsePrevents changes and removes the group from the Tab order.
hoverPreviewbooleantruePreview the value under the pointer before clicking.
orientation"horizontal" | "vertical""horizontal"The axis pointer positions are measured along for half steps.
requiredbooleanfalseSets aria-required on the group.
Data attributeValue
[data-rating-group-root]Present
[data-orientation]"horizontal" | "vertical"
[data-disabled]Present when disabled
[data-readonly]Present when readonly

RatingGroupItem

One visual step. role="presentation" — the root carries the semantics. Fill it with an icon and style against data-state. Renders a star that fills while active, unless you pass children of your own. Renders a Div; extra props are forwarded onto it.

PropTypeDefaultDescription
index*numberZero-based position; the item represents the rating index + 1.
disabledSignal<boolean> | booleanfalseIgnores pointer input on this item.
Data attributeValue
[data-rating-group-item]Present
[data-state]"active" | "partial" | "inactive"
[data-value]The rating the item represents
[data-orientation]"horizontal" | "vertical"
[data-disabled]Present when disabled
[data-readonly]Present when readonly