---
title: "Rating"
description: "A star-rating input where the user selects a score, with support for fractional values."
canonical_url: "https://vinicunca.dev/akar/components/rating"
---
# Rating

> A star-rating input where the user selects a score, with support for fractional values.

```vue [index.vue]
<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>
```

```css [styles.css]
@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.

```bash [pnpm]
pnpm add akar
```

```bash [yarn]
yarn add akar
```

```bash [npm]
npm install akar
```

```bash [bun]
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.

```vue
<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](https://vinicunca.dev/akar/components/radio-group) under the hood, so it supports form submission and keyboard navigation.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |
| `clearable` |  | `boolean` | When `true`, clicking the currently selected rating resets the value to `0`. |
| `defaultValue` |  | `number` | The 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.<br><br>If omitted, inherits globally from `ConfigProvider` or assumes LTR (left-to-right) reading mode. |
| `disabled` |  | `boolean` | When `true`, prevents the user from interacting with radio items. |
| `hoverable` |  | `boolean` | When `true`, the rating previews the value under the pointer on hover. |
| `length` | `5` | `number` | The number of rating items to render. |
| `loop` |  | `boolean` | When `true`, keyboard navigation will loop from last item to first, and vice versa. |
| `modelValue` |  | `number` | The controlled rating value. Can be bound with `v-model`. |
| `name` |  | `string` | The 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` |  | `boolean` | When `true`, indicates that the user must set the value before the owning form can be submitted. |
| `step` | `1` | `1 \| 0.5 \| 0.25 \| 0.1` | The granularity each rating item is divided into. |

**Events**

| Event | Payload | Description |
| --- | --- | --- |
| `update:modelValue` | `payload: number` | Event handler called when the value changes |

**Slots**

| Slot | Payload | Description |
| --- | --- | --- |
| `modelValue` | `number` |  |
| `items` | `number[]` |  |

[RatingRoot.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Rating/RatingRoot.vue)

| 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.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"label"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |
| `item*` |  | `number` | The 1-based index of this item within the rating (e.g. the 3rd star). |

**Slots**

| Slot | Payload | Description |
| --- | --- | --- |
| `steps` | `number[]` |  |

[RatingItem.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Rating/RatingItem.vue)

### 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.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |
| `step*` |  | `number` | The step value this indicator represents. |

[RatingItemIndicator.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Rating/RatingItemIndicator.vue)

| 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:

```vue
<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.

```vue
<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.

```vue
<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.

```vue
<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`.

```vue
<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.

```vue
<template>
  <RatingRoot
    :default-value="4"
    disabled
  >
    <!-- ... -->
  </RatingRoot>
</template>
```

## Accessibility

Built on top of the [Radio Group](https://vinicunca.dev/akar/components/radio-group) primitive and adheres to the [Radio Group WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/radio). Provide an accessible label for each step via `aria-label` so screen reader users understand the value each indicator represents.

### Keyboard Interactions

| Key | Description |
| --- | --- |
| <kbd>Tab</kbd> | Moves focus to either the checked item or the first item in the rating. |
| <kbd>Space</kbd> | When focus is on an unchecked item, selects that value. |
| <kbd>ArrowDown</kbd> | Moves focus and selection to the next item. |
| <kbd>ArrowRight</kbd> | Moves focus and selection to the next item. |
| <kbd>ArrowUp</kbd> | Moves focus and selection to the previous item. |
| <kbd>ArrowLeft</kbd> | Moves focus and selection to the previous item. |

---

- [ARIA](https://www.w3.org/WAI/ARIA/apg/patterns/radio)
- [GitHub](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Rating)
- [npm](https://www.npmjs.com/package/akar)


## Sitemap

See the full [sitemap](https://vinicunca.dev/sitemap.md) for all pages.
