# Vue Star Rate — Full Reference (vue-js-star-rating) > Zero-dependency Vue 3.5+ star rating component. Keyboard accessible. TypeScript-first. Half-star precision. Lucide / FontAwesome / custom icon providers. SSR & Nuxt 3 ready. This document is the long-form, LLM-optimized reference: install steps, every prop, every event, every slot, accessibility notes, performance notes, frequently asked questions, and migration guidance — flattened into a single text file for retrieval-augmented generation (RAG) and chat-style answer engines. --- ## 1. Summary | Field | Value | | --- | --- | | npm package | `vue-js-star-rating` | | Current version | 3.1.1 (2026-10-19) | | License | MIT | | Author | Pooya Golchian — https://pooya.blog | | Repo | https://github.com/pooyagolchian/vue-star-rate | | Docs / live demo | https://pooyagolchian.github.io/vue-star-rate/ | | Peer dep | `vue ^3.5.0` | | Runtime deps | none | | Optional peers | none (see section 10 for the caveat about releases 2.0.0 to 3.1.0) | | Bundle size | `import { VueStarRate }`: about 4.6 KB gzipped JavaScript (12.4 KB raw) plus 0.75 KB gzipped CSS (2.9 KB raw); all three icon providers included, nothing lazy-loaded. `useStarRating` alone: about 1 KB gzipped. See section 10 | | Node engines | >= 18 | | Module formats | ESM (`vue-star-rate.js`) + UMD (`vue-star-rate.umd.cjs`) + d.ts | | Accessibility | Keyboard navigation, ARIA group with per-star buttons, `prefers-reduced-motion`. Not audited against WCAG; known gaps are listed in section 11 | | SSR | safe (all three icon providers render server-side; nothing is loaded asynchronously) | | Nuxt 3 | compatible — no `` wrapper needed | --- ## 2. Installation ```bash # pnpm (recommended) pnpm add vue-js-star-rating # npm npm install vue-js-star-rating # yarn yarn add vue-js-star-rating ``` There are no optional peers: `vue ^3.5.0` is the only peer dependency, and `lucide-vue-next` is not needed. `icon-provider="lucide"` draws Lucide's own star geometry inline as an SVG, so there is nothing to install for it. (Releases 2.0.0 to 3.1.0 are the exception: they import it, so builds fail unless `lucide-vue-next` is installed, see section 10.) `icon-provider="fontawesome"` renders `` elements with Font Awesome class names, so your app must load Font Awesome's stylesheet itself. Without it the stars are invisible. For example, with `@fortawesome/fontawesome-free` installed in your app: ```bash pnpm add @fortawesome/fontawesome-free ``` ```ts import '@fortawesome/fontawesome-free/css/all.min.css'; ``` --- ## 3. Quick start ```vue ``` ### Global plugin registration ```ts // main.ts import { createApp } from 'vue'; import App from './App.vue'; import VueStarRatePlugin from 'vue-js-star-rating'; import 'vue-js-star-rating/dist/style.css'; createApp(App).use(VueStarRatePlugin).mount('#app'); ``` --- ## 4. Props (complete) | Prop | Type | Default | Description | | --- | --- | --- | --- | | `v-model` / `modelValue` | `number` | `0` | Current rating value | | `maxStars` | `number` | `5` | Maximum number of stars | | `allowHalf` | `boolean` | `false` | Enable 0.5-step ratings | | `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | Size preset (16 / 20 / 24 / 32 / 40 px) | | `iconSize` | `number \| { width: number; height: number }` | auto | Override pixel size | | `iconProvider` | `'custom' \| 'lucide' \| 'fontawesome'` | `'custom'` | Icon renderer (custom uses the bundled SVG fallback when no slot is provided; fontawesome needs Font Awesome's stylesheet loaded by your app) | | `colors` | `Partial` | see below | Color configuration | | `animation` | `Partial` | see below | Animation configuration | | `readonly` | `boolean` | `false` | Disable user interaction (clickable false, focusable true) | | `disabled` | `boolean` | `false` | Disable + grey out the entire component | | `clearable` | `boolean` | `false` | Show a clear button when the rating is above `minRating` (hidden when `readonly` or `disabled`) | | `allowReset` | `boolean` | `true` | Click the active star again to reset | | `showCounter` | `boolean` | `false` | Show the rating counter | | `counterTemplate` | `string` | `'{value} / {max}'` | Counter template; tokens `{value}` and `{max}` are replaced | | `showTooltip` | `boolean` | `false` | Show `title` tooltips on star hover | | `tooltipLabels` | `string[]` | — | Custom tooltip text per star (index-based) | | `minRating` | `number` | `0` | Minimum selectable value | | `step` | `number` | `1` | Increment step (overridden by `allowHalf`) | | `rtl` | `boolean` | `false` | Right-to-left layout. Known gap: the half-star fill is still painted on the left side of the star and `ArrowLeft` / `ArrowRight` are not mirrored; pointer clicks on half stars are mirrored | | `inline` | `boolean` | `false` | Accepted but not implemented (no visual effect) | | `gap` | `number` | `4` | Gap between stars in pixels | | `ariaLabel` | `string` | `'Star rating'` | Accessible group label | | `className` | `string` | — | Extra CSS class on the root element | | `faIcons` | `{ empty?: string; filled?: string; half?: string }` | — | FontAwesome class overrides | | `customIcon` | `CustomIconRenderer` | — | Not implemented: declared in the types, but the component ignores it. Use the `icon` slot instead | ### `StarColors` interface ```ts interface StarColors { empty: string; // default '#d1d5db' filled: string; // default '#fbbf24' hover: string; // default '#f59e0b' half?: string; // default '#fbbf24' (fixed; does not follow a custom filled color) } ``` ### `AnimationConfig` interface ```ts interface AnimationConfig { enabled: boolean; // default true duration: number; // default 200 ms type: 'scale' | 'bounce' | 'pulse' | 'none'; // default 'scale' } ``` The hover animations are switched off when the user has `prefers-reduced-motion: reduce` set at the OS level. `enabled: false` and `type: 'none'` are not a full off-switch: on interactive stars the base hover transition and `scale(1.1)` remain unless the user prefers reduced motion. Because of that base scale, `type: 'scale'` (1.2) only differs from `'none'` on read-only and disabled stars, which have no base hover scale and so do stop animating with `enabled: false`; `'bounce'` and `'pulse'` play on hover for every star. --- ## 5. Events | Event | Payload | Description | | --- | --- | --- | | `update:modelValue` | `number` | Emitted whenever the committed rating changes through the component (click, keyboard, `setRating()`, `reset()`); not emitted when the parent itself changes `v-model` | | `change` | `(value: number, oldValue: number)` | Emitted right after `update:modelValue`, on the same occasions (click, keyboard, `setRating()`, `reset()`); external `v-model` writes do not re-emit | | `hover` | `number \| null` | Previewed value while the pointer is over the stars; `null` when it leaves them | | `focus` | `()` | Root element received focus (not emitted when focus lands directly on a star button) | | `blur` | `()` | Root element lost focus (also emitted when focus moves onto a star button inside it) | --- ## 6. Slots | Slot | Scoped props | Description | | --- | --- | --- | | `icon` | `{ filled, half, size, color, index }` | Custom icon per star (used when `iconProvider="custom"`) | | `counter` | `{ value, max }` | Custom counter content | | `clear` | — | Custom clear button content | --- ## 7. Keyboard navigation | Key | Action | | --- | --- | | `→`, `↑` | Increase rating by step | | `←`, `↓` | Decrease rating by step | | `Home` | Set to `minRating` | | `End` | Set to `maxStars` | | `1`–`9` | Jump to numeric value (ignored when greater than `maxStars`) | | `0` | Reset to `minRating` | --- ## 8. Exposed methods ```ts const star = ref>(); star.value?.reset(); // back to initial value star.value?.setRating(3.5); // set programmatically (with the default step and no allowHalf, 3.5 snaps to 4) star.value?.getRating(); // current value star.value?.focus(); // focus the root element star.value?.blur(); // remove focus ``` --- ## 9. Composable — `useStarRating` Headless API exported alongside the component: ```ts import { useStarRating } from 'vue-js-star-rating'; const { stars, // computed StarItem[] displayRating, // computed number (hover-aware) isHovering, isFocused, handleClick, handleMouseEnter, handleMouseLeave, handleKeyDown, reset, setRating, getRating, setFocused, } = useStarRating(options, emit); ``` Options accept `MaybeRefOrGetter` for full reactivity. --- ## 10. Bundle composition Both entry files (ESM and UMD) import only `vue` and contain all three icon providers: the built-in SVG star, Lucide's star (drawn inline) and the Font Awesome `` renderer. Nothing is lazy-loaded: there is no dynamic `import()`, no async chunk and no per-provider code splitting. Measured with Vite 6 and esbuild minification, `vue` external, gzip -9: | Import | Cost | | --- | --- | | `import { VueStarRate } from 'vue-js-star-rating'` | about 12.4 KB raw / 4.6 KB gzipped JavaScript, plus 2.9 KB raw / 0.75 KB gzipped CSS (`vue-js-star-rating/dist/style.css`) | | `import { useStarRating } from 'vue-js-star-rating'` | about 1 KB gzipped JavaScript | Export-level tree-shaking works, which is why `useStarRating` alone is small. There is no component-level code splitting: importing `VueStarRate` includes all three icon providers, whichever `iconProvider` you use. History: version 3.1.0 claimed lazy-loaded icon chunks and documented `lucide-vue-next` as an optional peer. That was wrong. Its entry file contained `import("lucide-vue-next")`, which bundlers resolve at build time, so Vite, webpack, esbuild, Nuxt and Storybook builds fail unless `lucide-vue-next` is installed (GitHub issue #13; issue #7 had been closed earlier with the same wrong claim). This is fixed in 3.1.1; see CHANGELOG.md. --- ## 11. Accessibility notes - Container: `role="group"` + `aria-label` (configurable via `ariaLabel`); `aria-disabled` reflects the `disabled` prop; `tabindex="0"` for keyboard focus (`-1` when disabled). - Stars: each is a `