<script setup lang="ts">
import { RatingItem, RatingItemIndicator, RatingRoot } from 'akar';
import { ref } from 'vue';
import './styles.css';
const rating = ref(3);
</script>
<template>
<div class="akar-demo akar-demo-Rating">
<RatingRoot
v-slot="{ items }"
v-model="rating"
class="RatingRoot"
>
<RatingItem
v-for="item in items"
:key="item"
v-slot="{ steps }"
:item="item"
class="RatingItem"
>
<RatingItemIndicator
v-for="step in steps"
:key="step"
:step="step"
:aria-label="`Rate ${step}`"
class="RatingItemIndicator"
>
<PIcon
name="i-lucide-star"
class="RatingStar"
/>
</RatingItemIndicator>
</RatingItem>
</RatingRoot>
</div>
</template>@scope (.akar-demo-Rating) {
.RatingRoot {
display: flex;
gap: 4px;
}
.RatingItem {
position: relative;
width: 32px;
height: 32px;
cursor: pointer;
transition: transform 150ms ease-out;
}
.RatingItem:hover {
transform: scale(1.1);
}
.RatingItemIndicator {
position: absolute;
overflow: hidden;
border-radius: 4px;
color: #e7e5e4;
transition: color 150ms;
width: var(--akar-rating-item-step-width);
opacity: var(--akar-rating-item-step-opacity);
z-index: var(--akar-rating-item-step-z-index);
}
.RatingItemIndicator[data-state='active'] {
color: hsl(142.1 70.6% 45.3%);
filter: drop-shadow(0 1px 4px hsl(142.1 70.6% 45.3% / 0.5));
}
.RatingItemIndicator:focus-visible {
outline: 2px solid hsl(142.1 70.6% 45.3%);
outline-offset: 2px;
}
.RatingStar {
width: 32px;
height: 32px;
}
}Features
- Can be controlled or uncontrolled.
- Supports fractional ratings (half, quarter, etc.) via the step prop.
- Previews the value under the pointer on hover.
- Can be cleared by clicking the active value again.
- Built on top of Radio Group — full keyboard navigation and form support.
- Supports Right to Left direction.
- Exposes CSS variables for rendering partial steps.
Installation
Install the component from your command line.
pnpm add akar
yarn add akar
npm install akar
bun add akar
Anatomy
Import all parts and piece them together. RatingRoot exposes the list of items, and each RatingItem exposes the steps it is made of, so you render an indicator per step.
<script setup>
import { RatingItem, RatingItemIndicator, RatingRoot } from 'akar';
</script>
<template>
<RatingRoot v-slot="{ items }">
<RatingItem
v-for="item in items"
:key="item"
v-slot="{ steps }"
:item="item"
>
<RatingItemIndicator
v-for="step in steps"
:key="step"
:step="step"
/>
</RatingItem>
</RatingRoot>
</template>
API Reference
Root
Contains all the parts of a rating and provides the rating state. Renders a Radio Group under the hood, so it supports form submission and keyboard navigation.
| Prop | Default | Type |
|---|---|---|
as | "div" | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
clearable | booleanWhen | |
defaultValue | numberThe rating value when initially rendered. Use when you do not need to control the state of the rating. | |
dir | "ltr" | "rtl"The reading direction of the combobox when applicable. If omitted, inherits globally from | |
disabled | booleanWhen | |
hoverable | booleanWhen | |
length | 5 | numberThe number of rating items to render. |
loop | booleanWhen | |
modelValue | numberThe controlled rating value. Can be bound with | |
name | stringThe name of the field. Submitted with its owning form as part of a name/value pair. | |
orientation | "horizontal" | "vertical" | "horizontal"The orientation of the component. |
required | booleanWhen | |
step | 1 | 1 | 0.5 | 0.25 | 0.1The granularity each rating item is divided into. |
| Event | Payload |
|---|---|
update:modelValue | payload: numberEvent handler called when the value changes |
| Slot (default) | Payload |
|---|---|
modelValue | number |
items | number[] |
| Data attribute | Value |
|---|---|
[data-disabled] | Present when disabled |
[data-orientation] | "vertical" | "horizontal" |
Item
Wraps a single rating value (e.g. a single star). It computes the list of steps that compose this item based on the root's step prop, exposed via the default slot. Renders a label by default.
| Prop | Default | Type |
|---|---|---|
as | "label" | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
item* | numberThe 1-based index of this item within the rating (e.g. the 3rd star). |
| Slot (default) | Payload |
|---|---|
steps | number[] |
ItemIndicator
The interactive indicator rendered for each step of an item. It reflects whether the step is active based on the current (or hovered) value.
| Prop | Default | Type |
|---|---|---|
as | "div" | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
step* | numberThe step value this indicator represents. |
| Data attribute | Value |
|---|---|
[data-state] | "active" |
[data-disabled] | Present when disabled |
To render partial steps (for step values below 1), RatingItemIndicator exposes the following CSS variables:
| CSS Variable | Description |
|---|---|
--akar-rating-item-step-width | The width this step should occupy within the item, e.g. 50% for a half step. |
--akar-rating-item-step-opacity | 1 when the step should be visible, 0 otherwise (used to stack overlapping steps). |
--akar-rating-item-step-z-index | The stacking order of the step so smaller steps render above larger ones. |
A typical fractional indicator clips its width and stacks steps using these variables:
<RatingItemIndicator
:step="step"
class="absolute overflow-hidden w-[var(--akar-rating-item-step-width)] opacity-[var(--akar-rating-item-step-opacity)] z-[var(--akar-rating-item-step-z-index)]"
/>
Examples
Fractional rating
Use the step prop to allow values smaller than 1. Each RatingItem is then split into multiple steps, and each step renders its own indicator clipped with the exposed CSS variables.
<script setup>
import { RatingItem, RatingItemIndicator, RatingRoot } from 'akar'
import { ref } from 'vue'
const rating = ref(2.5)
</script>
<template>
<RatingRoot
v-slot="{ items }"
v-model="rating"
:step="0.5"
>
<RatingItem
v-for="item in items"
:key="item"
v-slot="{ steps }"
:item="item"
class="relative"
>
<RatingItemIndicator
v-for="step in steps"
:key="step"
:step="step"
class="absolute overflow-hidden w-[var(--akar-rating-item-step-width)] opacity-[var(--akar-rating-item-step-opacity)] z-[var(--akar-rating-item-step-z-index)]"
/>
</RatingItem>
</RatingRoot>
</template>
Clearable
Use the clearable prop to let users reset the rating to 0 by clicking the currently selected value again.
<template>
<RatingRoot
v-model="rating"
clearable
>
<!-- ... -->
</RatingRoot>
</template>
Hover preview
Use the hoverable prop to preview the value under the pointer before committing to it. The RatingItemIndicator exposes data-state="active" for every step at or below the hovered value.
<template>
<RatingRoot
v-model="rating"
hoverable
>
<!-- ... -->
</RatingRoot>
</template>
Custom length
Use the length prop to change how many items are rendered. It defaults to 5.
<template>
<RatingRoot
v-model="rating"
:length="10"
>
<!-- ... -->
</RatingRoot>
</template>
Read-only / disabled
Use the disabled prop to prevent interaction, for example when displaying an average rating.
<template>
<RatingRoot
:default-value="4"
disabled
>
<!-- ... -->
</RatingRoot>
</template>
Accessibility
Built on top of the Radio Group primitive and adheres to the Radio Group WAI-ARIA design pattern. Provide an accessible label for each step via aria-label so screen reader users understand the value each indicator represents.
Keyboard Interactions
| Key | Description |
|---|---|
| Tab | Moves focus to either the checked item or the first item in the rating. |
| Space | When focus is on an unchecked item, selects that value. |
| ArrowDown | Moves focus and selection to the next item. |
| ArrowRight | Moves focus and selection to the next item. |
| ArrowUp | Moves focus and selection to the previous item. |
| ArrowLeft | Moves focus and selection to the previous item. |