Rating
A star rating that displays a fractional average or collects a whole score with the mouse or keyboard.
vue
<script setup lang="ts">
import SaRating from '@shared/components/common/SaRating.vue'
</script>
<template>
<div class="flex flex-col gap-3">
<div v-for="n in 5" :key="n" class="flex items-center gap-4">
<SaRating :model-value="n" readonly />
<span class="text-sm text-muted-foreground">{{ n }}.0</span>
</div>
</div>
</template>Usage
Import SaRating and bind a number with v-model. The value starts at 0, which means not rated.
vue
<script setup lang="ts">
import SaRating from '@shared/components/common/SaRating.vue'
import { ref } from 'vue'
const score = ref(0)
</script>
<template>
<SaRating v-model="score" label="Product rating" />
</template>Examples
Read-only and fractional
Add readonly to display a score. A read-only rating can show fractions: 4.3 fills the fifth star 30%. show-value prints the number beside the stars, with one decimal when the value has one.
vue
<script setup lang="ts">
import SaRating from '@shared/components/common/SaRating.vue'
</script>
<template>
<div class="flex flex-col gap-3">
<SaRating :model-value="4.3" readonly show-value />
<SaRating :model-value="3.7" readonly show-value />
<SaRating :model-value="2.5" readonly show-value />
<SaRating :model-value="0.6" readonly show-value />
</div>
</template>Sizes
size takes sm (16px stars), md (20px, the default) or lg (28px).
vue
<script setup lang="ts">
import SaRating from '@shared/components/common/SaRating.vue'
</script>
<template>
<div class="flex flex-wrap items-center gap-6">
<SaRating :model-value="4" size="sm" readonly />
<SaRating :model-value="4" readonly />
<SaRating :model-value="4" size="lg" readonly />
<SaRating :model-value="4.6" size="lg" readonly show-value />
</div>
</template>Interactive
Without readonly, hovering previews a score and clicking sets it. Clicking the current score again clears it back to 0.
vue
<script setup lang="ts">
import SaRating from '@shared/components/common/SaRating.vue'
import { Button } from '@shared/components/ui/button'
import { ref } from 'vue'
const score = ref(0)
</script>
<template>
<div class="flex items-center gap-4">
<SaRating v-model="score" size="lg" label="Rate this template" />
<Button variant="outline" size="sm" :disabled="score === 0" @click="score = 0">
Clear
</Button>
</div>
<p class="mt-2 text-sm text-muted-foreground">
{{ score === 0 ? 'Not rated yet' : `You rated ${score} of 5` }}
</p>
</template>Custom maximum
max sets the number of stars. It defaults to 5.
vue
<script setup lang="ts">
import SaRating from '@shared/components/common/SaRating.vue'
import { ref } from 'vue'
const score = ref(7)
</script>
<template>
<div class="flex flex-col gap-3">
<SaRating v-model="score" :max="10" label="Score out of ten" />
<SaRating :model-value="3" :max="3" readonly />
</div>
</template>Disabled
disabled dims the stars to 50% and ignores clicks and keys.
vue
<script setup lang="ts">
import SaRating from '@shared/components/common/SaRating.vue'
</script>
<template>
<SaRating :model-value="3" disabled label="Rating locked" />
</template>API
Source: src/shared/components/common/SaRating.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue | number | 0 | The current rating. Fractional values render partial stars when read-only. |
max | number | 5 | Number of stars. |
size | 'sm' | 'md' | 'lg' | 'md' | Star size: 16px, 20px or 28px. |
readonly | boolean | false | Display only: no hover, no focus, no pointer. |
disabled | boolean | false | Dims the stars and blocks input. |
showValue | boolean | false | Shows the numeric value beside the stars. |
label | string | — | Accessible name for the group. Falls back to the common.rating translation ("Rating" in English). |
Emits
| Event | Payload | Description |
|---|---|---|
update:modelValue | value: number | Fires on click and on keyboard input. 0 when the current score is cleared. |
Slots
None.
Accessibility
- Interactive (neither
readonlynordisabled): the stars group hasrole="slider", thelabelas its name, andaria-valuenow,aria-valuemin="0"andaria-valuemaxset tomax. The group is one tab stop. Each star is a button named "1 of 5", "2 of 5" and so on. - Keyboard:
ArrowUpandArrowRightadd one,ArrowDownandArrowLeftremove one,Homesets0andEndsetsmax. In a right-to-left layoutArrowRightandArrowLeftswap, so the arrow keys follow the reading direction. - Read-only or disabled: the group has
role="img"and a name such as "Rating: 4 out of 5". It takes no focus. A disabled rating also setsaria-disabled="true". - The partial fill grows from the start edge using logical properties, so fractions read correctly in right-to-left layouts.