Rating Group
Rating group allows a user to assign rating to an item within a product.
Features
- Support for syncing disabledstate of withfieldsetelement
- Support for form resetevents
Installation
To use the rating group machine in your project, run the following command in your command line:
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
To set up the rating correctly, you'll need to understand its anatomy and how we name its parts.
Each part includes a
data-partattribute to help identify them in the DOM.
Usage
First, import the rating package into your project
import * as rating from "@zag-js/rating-group"
The rating package exports two key functions:
- machine— The state machine logic for the rating widget.
- connect— The function that translates the machine's state to JSX attributes and event handlers.
You'll also need to provide a unique
idto theuseMachinehook. This is used to ensure that every part has a unique identifier.
Next, import the required hooks and functions for your framework and use the rating machine in your project 🔥
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>
Disabling the rating group
To make rating disabled, set the context's disabled property to true
const service = useMachine(rating.machine, { disabled: true, })
Making the rating readonly
To make rating readonly, set the context's readOnly property to true
const service = useMachine(rating.machine, { readOnly: true, })
Setting the initial value
Use the defaultValue property to set the rating's initial value.
const service = useMachine(rating.machine, { defaultValue: 2.5, })
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' }, })
Usage within forms
To use rating within forms, use the exposed inputProps from the connect
function and ensure you pass name value to the machine's context. It will
render a hidden input and ensure the value changes get propagated to the form
correctly.
const service = useMachine(rating.machine, { name: "rating", })
Styling guide
Earlier, we mentioned that each rating part has a data-part attribute added to
them to select and style them in the DOM.
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:
- ids- Partial<{ root: string; label: string; hiddenInput: string; control: string; item(id: string): string; }>The ids of the elements in the rating. Useful for composition.
- translations- IntlTranslationsSpecifies the localized strings that identifies the accessibility elements and their states
- count- numberThe total number of ratings.
- name- stringThe name attribute of the rating element (used in forms).
- form- stringThe associate form of the underlying input element.
- value- numberThe controlled value of the rating
- defaultValue- numberThe initial value of the rating when rendered. Use when you don't need to control the value of the rating.
- readOnly- booleanWhether the rating is readonly.
- disabled- booleanWhether the rating is disabled.
- required- booleanWhether the rating is required.
- allowHalf- booleanWhether to allow half stars.
- autoFocus- booleanWhether 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.
- id- stringThe 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 group
- clearValue- () => voidClears the value of the rating group
- hovering- booleanWhether the rating group is being hovered
- value- numberThe current value of the rating group
- hoveredValue- numberThe value of the currently hovered rating
- count- numberThe total number of ratings
- items- number[]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.
Edit this page on GitHub