Rating Group
Rating group lets users assign a rating value to an item.
Features
- Syncs with
disabledstate offieldset - Supports form
resetevents
Installation
Install the rating group package:
npm install @zag-js/rating-group @zag-js/react # or yarn add @zag-js/rating-group @zag-js/react
npm install @zag-js/rating-group @zag-js/solid # or yarn add @zag-js/rating-group @zag-js/solid
npm install @zag-js/rating-group @zag-js/vue # or yarn add @zag-js/rating-group @zag-js/vue
npm install @zag-js/rating-group @zag-js/svelte # or yarn add @zag-js/rating-group @zag-js/svelte
Anatomy
Check the rating anatomy and part names.
Each part includes a
data-partattribute to help identify them in the DOM.
Usage
Import the rating package:
import * as rating from "@zag-js/rating-group"
The rating package exports two key functions:
machine- State machine logic.connect- Maps machine state to JSX props and event handlers.
Then use the framework integration helpers:
import * as rating from "@zag-js/rating-group" import { useMachine, normalizeProps } from "@zag-js/react" import { HalfStar, Star } from "./icons" function Rating() { const service = useMachine(rating.machine, { id: "1" }) const api = rating.connect(service, normalizeProps) return ( <div {...api.getRootProps()}> <label {...api.getLabelProps()}>Rate:</label> <div {...api.getControlProps()}> {api.items.map((index) => { const state = api.getItemState({ index }) return ( <span key={index} {...api.getItemProps({ index })}> {state.half ? <HalfStar /> : <Star />} </span> ) })} </div> <input {...api.getHiddenInputProps()} /> </div> ) }
import * as rating from "@zag-js/rating-group" import { useMachine, normalizeProps } from "@zag-js/solid" import { createMemo, createUniqueId } from "solid-js" import { HalfStar, Star } from "./icons" function Rating() { const service = useMachine(rating.machine, { id: createUniqueId() }) const api = createMemo(() => rating.connect(service, normalizeProps)) return ( <div {...api().getRootProps()}> <label {...api().getLabelProps()}>Rate:</label> <div {...api().getControlProps()}> {api().items.map((index) => { const state = api().getItemState(index) return ( <span key={index} {...api().getItemProps({ index })}> {state.half ? <HalfStar /> : <Star />} </span> ) })} </div> <input {...api().getHiddenInputProps()} /> </div> ) }
<script setup> import * as rating from "@zag-js/rating-group" import { normalizeProps, useMachine } from "@zag-js/vue" import { computed } from "vue" import { HalfStar, Star } from "./icons" const service = useMachine(rating.machine, { id: "1" }) const api = computed(() => rating.connect(service, normalizeProps)) </script> <template> <div v-bind="api.getRootProps()"> <label v-bind="api.getLabelProps()">Rate:</label> <div v-bind="api.getControlProps()"> <span v-for="index in api.items" :key="index" v-bind="api.getItemProps({ index })" > <HalfStar v-if="api.getItemState({ index }).half" /> <Star v-else /> </span> </div> <input v-bind="api.getHiddenInputProps()" /> </div> </template>
<script lang="ts"> import * as rating from "@zag-js/rating-group" import { normalizeProps, useMachine } from "@zag-js/svelte" const id = $props.id() const service = useMachine(rating.machine, { id, defaultValue: 2.5, }) const api = $derived(rating.connect(service, normalizeProps)) </script> <div {...api.getRootProps()}> <label {...api.getLabelProps()}>Rate:</label> <div {...api.getControlProps()}> {#each api.items as index} {@const snapshot = api.getItemState({ index })} <span {...api.getItemProps({ index })}> {#if snapshot.half} {@render HalfStar()} {:else} {@render Star()} {/if} </span> {/each} </div> <input {...api.getHiddenInputProps()} data-testid="hidden-input" /> </div>
Setting the initial value
Use the defaultValue property to set the rating's initial value.
const service = useMachine(rating.machine, { defaultValue: 2.5, })
Controlled rating value
Use value and onValueChange to control the rating externally.
const service = useMachine(rating.machine, { value, onValueChange(details) { setValue(details.value) }, })
Setting and clearing value programmatically
Use api.setValue or api.clearValue when you need imperative control.
api.setValue(4) api.clearValue()
Allowing half ratings
Enable allowHalf when your UX needs fractional ratings.
const service = useMachine(rating.machine, { allowHalf: true, })
Listening for changes
When the rating value changes, the onValueChange callback is invoked.
const service = useMachine(rating.machine, { onValueChange({ value }) { console.log("rating value is:", value) // 1 | 2.5 | 4 }, })
Listening for hover changes
Use onHoverChange to react to hover previews before selection.
const service = useMachine(rating.machine, { onHoverChange(details) { console.log("hovered rating:", details.hoveredValue) }, })
Customizing screen reader value text
Use translations.ratingValueText to customize how each rating item is
announced.
const service = useMachine(rating.machine, { translations: { ratingValueText: (index) => `${index} out of 5`, }, })
Usage within forms
To use rating in forms, set name and render api.getHiddenInputProps().
const service = useMachine(rating.machine, { name: "rating", })
Styling guide
Each rating part includes a data-part attribute you can target in CSS.
Disabled State
When the rating is disabled, the data-disabled attribute is added to the
rating, control and label parts.
[data-part="rating"][data-disabled] { /* styles for rating disabled state */ } [data-part="label"][data-disabled] { /* styles for rating control disabled state */ } [data-part="input"][data-disabled] { /* styles for rating label disabled state */ }
Checked State
When the rating is checked, the data-checked attribute is added to the rating
part.
[data-part="rating"][data-checked] { /* styles for rating checked state */ }
Readonly State
When the rating is readonly, the data-readonly attribute is added to the
rating part.
[data-part="rating"][data-readonly] { /* styles for rating readonly state */ }
Highlighted
When a rating is highlighted, the data-highlighted attribute is added to the
rating part.
[data-part="rating"][data-highlighted] { /* styles for highlighted rating */ }
Half rating
When a rating is half, the data-half attribute is added to the rating part.
[data-part="rating"][data-half] { /* styles for half rating */ }
Methods and Properties
Machine Context
The rating group machine exposes the following context properties:
idsPartial<{ root: string; label: string; hiddenInput: string; control: string; item: (id: string) => string; }>The ids of the elements in the rating. Useful for composition.translationsIntlTranslationsSpecifies the localized strings that identifies the accessibility elements and their statescountnumberThe total number of ratings.namestringThe name attribute of the rating element (used in forms).formstringThe associate form of the underlying input element.valuenumberThe controlled value of the ratingdefaultValuenumberThe initial value of the rating when rendered. Use when you don't need to control the value of the rating.readOnlybooleanWhether the rating is readonly.disabledbooleanWhether the rating is disabled.requiredbooleanWhether the rating is required.allowHalfbooleanWhether to allow half stars.autoFocusbooleanWhether to autofocus the rating.onValueChange(details: ValueChangeDetails) => voidFunction to be called when the rating value changes.onHoverChange(details: HoverChangeDetails) => voidFunction to be called when the rating value is hovered.dir"ltr" | "rtl"The document's text/writing direction.idstringThe unique identifier of the machine.getRootNode() => ShadowRoot | Node | DocumentA root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.
Machine API
The rating group api exposes the following methods:
setValue(value: number) => voidSets the value of the rating groupclearValueVoidFunctionClears the value of the rating grouphoveringbooleanWhether the rating group is being hoveredvaluenumberThe current value of the rating grouphoveredValuenumberThe value of the currently hovered ratingcountnumberThe total number of ratingsitemsnumber[]The array of rating values. Returns an array of numbers from 1 to the max value.getItemState(props: ItemProps) => ItemStateReturns the state of a rating item
Data Attributes
Accessibility
Keyboard Interactions
- ArrowRightMoves focus to the next star, increasing the rating value based on the `allowHalf` property.
- ArrowLeftMoves focus to the previous star, decreasing the rating value based on the `allowHalf` property.
- EnterSelects the focused star in the rating group.