Value: 4
<script setup lang="ts">
import { ref } from 'vue'
import { Rating, Stack, Text } from '@hina-ui/vue'
const score = ref(4)
</script>
<template>
<Stack gap="sm" align="start">
<Rating v-model="score" size="lg" aria-label="Rating" />
<Text tone="muted" size="sm">Value: {{ score }}</Text>
</Stack>
</template>
Usage
import { Rating } from '@hina-ui/vue'
A rating is a row of stars: clicking a star picks that score, and hovering previews the stars up to it as filled. v-model binds the score and max sets the maximum score, 5 by default. The star count defaults to max; set stars to control it independently. Attributes it does not declare land on the group element that wraps the stars, so name it with aria-label or aria-labelledby.
Value: 0
<script setup lang="ts">
import { ref } from 'vue'
import { Rating, Stack, Text } from '@hina-ui/vue'
const score = ref(0)
</script>
<template>
<Stack gap="sm" align="start">
<Rating v-model="score" aria-label="Rating" />
<Text tone="muted" size="sm">Value: {{ score }}</Text>
</Stack>
</template>
Examples
Half stars
With step set to 0.5 every star splits into two halves, so scores such as 2.5 can be picked.
Value: 2.5
<script setup lang="ts">
import { ref } from 'vue'
import { Rating, Stack, Text } from '@hina-ui/vue'
const score = ref(2.5)
</script>
<template>
<Stack gap="sm" align="start">
<Rating v-model="score" :step="0.5" aria-label="Rating" />
<Text tone="muted" size="sm">Value: {{ score }}</Text>
</Stack>
</template>
Score scale and star count
max sets the maximum score and stars sets the displayed star count. With :max="10" :stars="5", each star represents 2 points and a value of 7 displays 3.5 stars.
step remains measured in stars: the default 1 selects whole stars, changing the score by 2 points; 0.5 changes it by 1 point. v-model, update:modelValue, and form values submitted through name always use the actual score. Read-only ratings fill proportionally, regardless of step.
7 / 10
8.6 / 10 · Read only
<script setup lang="ts">
import { ref } from 'vue'
import { Inline, Rating, Stack, Text } from '@hina-ui/vue'
const score = ref(7)
</script>
<template>
<Stack gap="md" align="start">
<Inline gap="sm">
<Rating v-model="score" :max="10" :stars="5" :step="0.5" aria-label="Rating" />
<Text tone="muted" size="sm">{{ score }} / 10</Text>
</Inline>
<Inline gap="sm">
<Rating :model-value="8.6" :max="10" :stars="5" readonly />
<Text tone="muted" size="sm">8.6 / 10 · Read only</Text>
</Inline>
</Stack>
</template>
Read-only display
readonly renders the rating as a display-only graphic; the value may be any decimal and the stars fill proportionally, which suits average scores.
4.3 from 128 ratings
<script setup lang="ts">
import { Inline, Rating, Text } from '@hina-ui/vue'
</script>
<template>
<Inline gap="sm">
<Rating :model-value="4.3" readonly />
<Text tone="muted" size="sm">4.3 from 128 ratings</Text>
</Inline>
</template>
Sizes
size has three steps, sm, md and lg.
<script setup lang="ts">
import { Rating, Stack } from '@hina-ui/vue'
</script>
<template>
<Stack align="start">
<Rating :model-value="3" size="sm" aria-label="Small" />
<Rating :model-value="3" size="md" aria-label="Medium" />
<Rating :model-value="3" size="lg" aria-label="Large" />
</Stack>
</template>
States
disabled disables the group; clearable is on by default, so clicking the picked star again resets to zero, and turning it off keeps the score.
<script setup lang="ts">
import { ref } from 'vue'
import { Rating, Stack } from '@hina-ui/vue'
const fixed = ref(3)
</script>
<template>
<Stack align="start">
<Rating :model-value="3" disabled aria-label="Disabled" />
<Rating v-model="fixed" :clearable="false" aria-label="Not clearable" />
</Stack>
</template>
In a form
Inside a FormField the label is linked to the row of stars through aria-labelledby, and the error message is rendered by the field; validation rules and submission belong to the Form. The value is 0 until a rating is given.
<script setup lang="ts">
import { reactive, ref } from 'vue'
import * as v from 'valibot'
import { Button, Form, FormField, Rating, Text } from '@hina-ui/vue'
const schema = v.object({
score: v.pipe(v.number(), v.minValue(1, 'Give it a rating first')),
})
const values = reactive({ score: 0 })
const saved = ref('')
async function save(data: unknown) {
await new Promise(resolve => setTimeout(resolve, 600))
saved.value = JSON.stringify(data)
}
</script>
<template>
<Form v-slot="{ submitting }" :values="values" :rules="schema" class="w-80" @submit="save">
<FormField name="score" label="Rating" required>
<Rating v-model="values.score" />
</FormField>
<Button type="submit" :loading="submitting" class="self-start">Submit review</Button>
<Text v-if="saved" tone="muted" size="sm">Submitted: {{ saved }}</Text>
</Form>
</template>
Behavior
- Clicking a star picks that score, and clicking the same star again resets to zero; hovering previews the stars up to the pointer as filled and leaving restores them.
- With focus on a star, the left and right arrow keys move focus and pick, as in a radio group.
- Color changes of the stars are transitioned.
Accessibility
- When interactive the group is
role="radiogroup"and every star or half star is arole="radio"with a localized name. - When read only the group is
role="img"named by the locale as “n out of m stars”. When the star count differs from the maximum score, radio options and read-only graphics use the actual score, such as “7 out of 10 points”. - Name the group with
aria-labeloraria-labelledby.
API
Props
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue | number | 0 | The score |
max | number | 5 | Positive maximum score; also determines the star count when stars is omitted |
stars | number | max | Displayed star count, a positive integer |
step | 1 | 0.5 | 1 | Step in stars; the score increment is max / stars * step |
clearable | boolean | true | Whether clicking the picked star again resets |
readonly | boolean | false | Whether the rating is display only |
name | string | — | Form field name |
size | 'sm' | 'md' | 'lg' | 'md' | Size |
disabled | boolean | false | Whether the rating is disabled |
class | string | — | Classes appended to the root element |
Events
| Event | Payload | Description |
|---|---|---|
update:modelValue | value: number | The score changed |