npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vue-js-star-rating

v3.1.0

Published

Zero-dependency Vue 3.5+ star rating component — WCAG 2.2 accessible, TypeScript-first, half-star precision, tree-shakeable lazy-loaded Lucide/FontAwesome/custom icons, SSR & Nuxt ready

Downloads

732

Readme


✨ Features

| Feature | Description | | -------------------------- | ----------------------------------------------------------------- | | 🎯 Half-star ratings | Precise 0.5-step ratings with visual half-fill support | | 📐 Size presets | Five built-in sizes — xs · sm · md · lg · xl | | 🎨 Custom colors | Per-state color tokens: empty, filled, hover, half | | 🔌 Icon providers | Lucide, FontAwesome, or bring your own via scoped slot/render fn | | ⌨️ Keyboard navigation | Arrow keys, Home, End, 0–9 — fully operable without mouse | | 🔒 Read-only mode | Display-only ratings for reviews and dashboards | | ♿ WCAG 2.2 accessible | role="group", aria-pressed per star, aria-live counter | | 🔷 TypeScript-first | Full generics, MaybeRefOrGetter<T> reactive options | | ⚡ Zero dependencies | No runtime deps — only Vue 3.5+ as a peer | | 🌐 RTL support | Right-to-left layout via :rtl="true" | | 🔁 Clearable / reset | Built-in clear button and allow-reset-on-reclick behaviour | | 🧩 Slots API | Override icon, counter, and clear button with your own markup |


📦 Installation

# pnpm (recommended)
pnpm add vue-js-star-rating

# npm
npm install vue-js-star-rating

# yarn
yarn add vue-js-star-rating

Requires Vue 3.5+. This package uses defineModel, useTemplateRef, and MaybeRefOrGetter — all stable in Vue 3.5. It has zero runtime dependencies.


🚀 Quick Start

<script setup lang="ts">
import { ref } from 'vue';
import { VueStarRate } from 'vue-js-star-rating';
import 'vue-js-star-rating/dist/style.css';

const rating = ref(0);
</script>

<template>
  <VueStarRate v-model="rating" />
</template>

Global Plugin Registration

// 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');

📖 Examples

Half-Star Ratings

<VueStarRate v-model="rating" :allow-half="true" :show-counter="true" />

Size Presets

<!-- Size Presets: xs(16px), sm(20px), md(24px), lg(32px), xl(40px) -->
<VueStarRate v-model="rating" size="xs" />
<VueStarRate v-model="rating" size="sm" />
<VueStarRate v-model="rating" size="md" />
<VueStarRate v-model="rating" size="lg" />
<VueStarRate v-model="rating" size="xl" />

<!-- Custom pixel size -->
<VueStarRate v-model="rating" :icon-size="28" />

Custom Colors

<VueStarRate
  v-model="rating"
  :colors="{
    empty: '#e5e7eb',
    filled: '#fbbf24',
    hover: '#fcd34d',
    half: '#fbbf24',
  }"
/>

Read-only Display

<VueStarRate v-model="rating" :readonly="true" :show-counter="true" />

Clearable Rating

<VueStarRate v-model="rating" :clearable="true" />

RTL Layout

<VueStarRate v-model="rating" :rtl="true" />

Icon Providers

<!-- Lucide icons (requires lucide-vue-next) -->
<VueStarRate v-model="rating" icon-provider="lucide" />

<!-- FontAwesome (requires @fortawesome/fontawesome-free CSS) -->
<VueStarRate v-model="rating" icon-provider="fontawesome" />

<!-- Custom slot icon -->
<VueStarRate v-model="rating" icon-provider="custom">
  <template #icon="{ filled, size, color }">
    <svg :width="size.width" :height="size.height" viewBox="0 0 24 24">
      <polygon points="12,2 15,9 22,9 17,14 19,21 12,17 5,21 7,14 2,9 9,9"
               :fill="filled ? color : 'none'" :stroke="color" stroke-width="2" />
    </svg>
  </template>
</VueStarRate>

Custom Star Count

<VueStarRate v-model="rating" :max-stars="10" />

Counter & Tooltips

<!-- Show counter -->
<VueStarRate v-model="rating" :show-counter="true" />

<!-- Custom counter template -->
<VueStarRate v-model="rating" :show-counter="true" counter-template="{value} / {max} stars" />

<!-- Tooltips on hover -->
<VueStarRate v-model="rating" :show-tooltip="true" />

<!-- Custom tooltip labels -->
<VueStarRate
  v-model="rating"
  :show-tooltip="true"
  :tooltip-labels="['Terrible', 'Bad', 'OK', 'Good', 'Excellent']"
/>

Full Configuration

<VueStarRate
  v-model="rating"
  :max-stars="5"
  :allow-half="true"
  :readonly="false"
  :show-counter="true"
  :show-tooltip="true"
  size="lg"
  :colors="{
    empty: '#27272a',
    filled: '#fbbf24',
    hover: '#fcd34d',
    half: '#fbbf24',
  }"
  :animation="{
    enabled: true,
    duration: 200,
    type: 'scale',
  }"
  @change="(val, old) => console.log(val, old)"
  @hover="(val) => console.log('hover:', val)"
/>

📋 Props API

| Prop | Type | Default | Description | | ------------------ | ------------------------------------------ | --------------------- | ---------------------------------------- | | v-model | number | 0 | Rating value | | maxStars | number | 5 | Maximum number of stars | | allowHalf | boolean | false | Enable half-star ratings | | size | 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' | 'md' | Size preset | | iconSize | number \| { width, height } | auto | Custom pixel size | | iconProvider | 'custom' \| 'lucide' \| 'fontawesome' | 'custom' | Icon renderer | | colors | Partial<StarColors> | see below | Color configuration | | animation | Partial<AnimationConfig> | see below | Animation configuration | | readonly | boolean | false | Disable user interaction | | disabled | boolean | false | Disable + grey out component | | clearable | boolean | false | Show a clear button when rating > 0 | | allowReset | boolean | true | Click active star again to reset | | showCounter | boolean | false | Show rating counter | | counterTemplate | string | '{value} / {max}' | Counter format template | | showTooltip | boolean | false | Show tooltips on star hover | | tooltipLabels | string[] | — | Custom tooltip labels per star | | minRating | number | 0 | Minimum selectable value | | step | number | 1 | Increment step (overridden by allowHalf) | | rtl | boolean | false | Right-to-left layout | | inline | boolean | false | Inline layout mode | | gap | number | 4 | Gap between stars in pixels | | ariaLabel | string | 'Star rating' | Accessible group label | | className | string | — | Extra CSS class on root element | | faIcons | { empty?, filled?, half? } | — | FontAwesome class overrides | | customIcon | CustomIconRenderer | — | Programmatic icon render function |

StarColors type

interface StarColors {
  empty:   string  // default '#d1d5db' — unfilled star
  filled:  string  // default '#fbbf24' — filled star
  hover:   string  // default '#f59e0b' — hovered star
  half?:   string  // default = filled  — half-filled star
}

AnimationConfig type

interface AnimationConfig {
  enabled:  boolean                               // default true
  duration: number                                // default 200 ms
  type:     'scale' | 'bounce' | 'pulse' | 'none' // default 'scale'
}

🎰 Slots

| Slot | Scoped props | Description | | --------- | -------------------------------------- | --------------------------- | | icon | { filled, half, size, color, index } | Custom icon per star | | counter | { value, max } | Custom counter content | | clear | — | Custom clear button content |


📡 Events

| Event | Payload | Description | | -------- | ------------------- | ---------------------------------- | | change | (value, oldValue) | Rating changed by user interaction | | hover | number \| null | Hover enters / leaves a star | | focus | — | Component received keyboard focus | | blur | — | Component lost focus |

update:modelValue is handled automatically by v-model / defineModel.


⌨️ Keyboard Navigation

| Key | Action | | ------- | ---------------------- | | | Increase rating | | | Decrease rating | | Home | Set to minimum | | End | Set to maximum | | 1-9 | Jump to specific value | | 0 | Reset to minimum |


🖥️ Exposed Methods

const ratingRef = ref<InstanceType<typeof VueStarRate>>();

ratingRef.value?.reset();          // Reset to initial value
ratingRef.value?.setRating(3.5);   // Set programmatically
ratingRef.value?.getRating();      // Get current value
ratingRef.value?.focus();          // Focus the component
ratingRef.value?.blur();           // Blur the component

🔄 Migrating from v2 to v3

Breaking Changes

| v2.x | v3.x | | --------------------------------- | --------------------------------------------------------- | | modelValue prop | Managed by defineModel — template syntax unchanged | | lucideIcons prop | Removed — use icon-provider="lucide" instead | | role="slider" on container | role="group" — WCAG 2.2 compliant | | animation: { scale: 1.15 } | animation: { type: 'scale' } — no numeric scale key | | peerDependencies: vue ^3.3.0 | peerDependencies: vue ^3.5.0 | | Options API data()/methods | Composition API + <script setup> / defineModel |

Animation Migration

<!-- v2 — scale was never a valid AnimationConfig key -->
:animation="{ enabled: true, duration: 200, scale: 1.15 }"

<!-- v3 — use type instead -->
:animation="{ enabled: true, duration: 200, type: 'scale' }"

📦 Bundle size & optional peers

vue-js-star-rating is zero-dependency at the package boundary. The default SVG icon ships inside the main bundle; Lucide and FontAwesome icon providers are loaded lazily via defineAsyncComponent, so their optional peers are only required — and only fetched at runtime — when you actually render them.

| What you import | What's pulled into your bundle | | --- | --- | | import { VueStarRate } from 'vue-js-star-rating' + default icon | Component + SVG star only (~3 KB gzipped) | | <VueStarRate icon-provider="lucide" /> | Above + a separate LucideIcon-[hash].js chunk + lucide-vue-next | | <VueStarRate icon-provider="fontawesome" /> | Above + a separate FontAwesomeIcon-[hash].js chunk | | <VueStarRate icon-provider="custom"><template #icon /></VueStarRate> | Component only — you supply the markup |

If you choose a non-Lucide provider, you do not need to install lucide-vue-next — the consumer bundler will not try to resolve it at build time. (Issue #7 regression test ships in tests/lazyIcons.spec.ts.)

# Only when you set icon-provider="lucide"
pnpm add lucide-vue-next

# Only when you set icon-provider="fontawesome"
# (the CSS classes the wrapper emits ship with the free pack)
pnpm add @fortawesome/fontawesome-free

❓ FAQ

Do I need lucide-vue-next if I use FontAwesome (or my own icon)?

No. Since v3.1.0, icon providers are loaded with defineAsyncComponent. The static dependency graph from import { VueStarRate } from 'vue-js-star-rating' does not include lucide-vue-next, so consumer bundlers (Vite, Webpack, Rollup, esbuild) will not require it to be installed.

Is it SSR-safe? Does it work with Nuxt 3?

Yes. The component renders deterministically on the server. Async icon providers resolve on the client after hydration — wrap your usage in <ClientOnly> (Nuxt) or <Suspense> if you need the icon present in the initial HTML, otherwise the default SVG provider works fully server-side.

What is the bundle size?

About 3 KB gzipped for the default SVG path (component + composable + types stripped). Lucide and FontAwesome chunks are emitted as separate files and only fetched when the matching provider is rendered.

Is it accessible?

The root carries role="group" + aria-label. Each star button exposes aria-pressed. The counter uses aria-live="polite" for live announcements. Full keyboard navigation: arrow keys, Home, End, 0–9. Animations are gated on prefers-reduced-motion since v3.1.0. Compliant with WCAG 2.2 Level AA.

Can I use it without v-model?

Yes — pass :model-value and listen to @change (or @update:modelValue). The composable useStarRating is also exported if you want headless control.

How do I clear the rating programmatically?

const star = ref<InstanceType<typeof VueStarRate>>();
star.value?.setRating(0); // or star.value?.reset()

⚖️ Comparison

| Feature | vue-js-star-rating | vue-star-rating | vue3-star-ratings | | --- | :---: | :---: | :---: | | Vue 3.5+ (defineModel) | ✅ | — | partial | | TypeScript-first | ✅ | — | partial | | Runtime dependencies | 0 | 1 | 1 | | Tree-shakeable lazy icons | ✅ | — | — | | Half-star precision | ✅ | ✅ | ✅ | | Keyboard navigation | ✅ (full) | partial | partial | | aria-pressed + aria-live | ✅ | — | — | | WCAG 2.2 compliant | ✅ | — | — | | RTL | ✅ | — | — | | prefers-reduced-motion | ✅ | — | — | | Custom icon via slot | ✅ | partial | — | | SSR / Nuxt 3 | ✅ | partial | ✅ |


🛠️ Development

# Clone the repository
git clone https://github.com/pooyagolchian/vue-star-rate.git
cd vue-star-rate

# Install dependencies
pnpm install

# Start development server
pnpm dev

# Run tests
pnpm test

# Build for production
pnpm build

# Documentation development
pnpm docs:dev

# Build documentation
pnpm docs:build

🤝 Contributing

Contributions are welcome! Please read our Contributing Guide for details on our code of conduct and the process for submitting pull requests.


📄 License

MIT © Pooya Golchian