Star ratings sound simple until you ship them to production. Then you need half-star precision, accessible keyboard navigation, RTL layouts, flexible icon sources, and correct ARIA semantics. I built vue-star-rate to handle all of that in a single zero-dependency Vue 3.5+ component.
Installation
pnpm add vue-js-star-rating
Requires Vue 3.5+. Uses defineModel and useTemplateRef, both stable in Vue 3.5. Zero runtime dependencies.
Basic Usage
<script setup lang="ts">
import 'vue-js-star-rating/dist/style.css';
const rating = ref(0);
</script>
<template>
</template>
Half-Star Ratings
The visual renderer fills exactly half of a star glyph. The emitted value is a decimal like 3.5.
Size Presets
<!-- 16px -->
<!-- 20px -->
<!-- 24px, default -->
<!-- 32px -->
<!-- 40px -->
<!-- Custom pixels -->
Custom Colors
Icon Providers
<!-- Lucide (requires lucide-vue-next) -->
<!-- FontAwesome (requires @fortawesome/fontawesome-free) -->
<!-- Fully custom SVG via slot -->
Read-Only Mode
For review cards, dashboards, and product pages:
Keyboard Navigation
| Key | Action |
|---|---|
| Arrow Right / Up | Increase rating |
| Arrow Left / Down | Decrease rating |
| Home | Set to minimum |
| End | Set to maximum |
| 1โ9 | Jump to specific value |
| 0 | Reset to minimum |
The component uses role="group", aria-pressed on each star, and an aria-live counter, fully WCAG 2.2 compliant.
Tooltips and Counters
Full Configuration Example
<VueStarRate
v-model="rating"
:max-stars="5"
:allow-half="true"
:show-counter="true"
:show-tooltip="true"
size="lg"
:colors="{ empty: '#27272a', filled: '#fbbf24', hover: '#fcd34d', half: '#fbbf24' }"
:animation="{ enabled: true, duration: 200, type: 'scale' }"
:clearable="true"
@change="(val, old) => console.log(val, old)"
/>
Props Reference
| Prop | Type | Default | Description |
|---|---|---|---|
v-model |
number |
0 |
Rating value |
maxStars |
number |
5 |
Maximum stars |
allowHalf |
boolean |
false |
Half-star precision |
size |
xs / sm / md / lg / xl |
md |
Size preset |
readonly |
boolean |
false |
Display-only mode |
clearable |
boolean |
false |
Clear button |
showCounter |
boolean |
false |
Numeric counter |
showTooltip |
boolean |
false |
Hover tooltips |
rtl |
boolean |
false |
Right-to-left layout |
iconProvider |
custom / lucide / fontawesome |
custom |
Icon source |
Programmatic Control
const ratingRef = ref<InstanceType<typeof VueStarRate>>();
ratingRef.value?.reset();
ratingRef.value?.setRating(3.5);
ratingRef.value?.getRating();
ratingRef.value?.focus();
Migration from v2
| v2 | v3 |
|---|---|
lucideIcons prop |
icon-provider="lucide" |
role="slider" |
role="group" (WCAG 2.2) |
animation: { scale: 1.15 } |
animation: { type: 'scale' } |
Vue ^3.3.0 peer dep |
Vue ^3.5.0 peer dep |
GitHub ยท npm ยท Full Documentation
Top comments (0)