Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

@mil-rlib/reactjs-star-rating

milayek8621MIT2.0.0TypeScript support: included

Ultra-lightweight React Star Rating - 889B brotli, half-star precision, zero dependencies

react-star-rating, half-star, star-rating, lightweight, performance, accessibility, typescript, zero-dependencies, reactjs, component, rating, stars, ui-component, frontend

readme

@mil-rlib/reactjs-star-rating

🌟 Ultra-lightweight React Star Rating Component - Professional-grade rating system with half-star precision, zero dependencies, and 889 bytes brotli compressed!

NPM Version Bundle Size NPM Downloads GitHub Stars License TypeScript Zero Dependencies

🔗 View Live Demo & Examples - Interactive playground showcasing all features

Why Choose This Component?

Ultra-Performance - Only 889 bytes brotli compressed, 75% smaller than alternatives
🎯 Half-Star Precision - Click detection on left/right star halves for 0.5 increments
Accessibility First - Complete ARIA support and screen reader compatibility
🎨 Highly Customizable - Extensive styling options with CSS-in-JS approach
📱 Mobile Ready - Perfect touch interactions and responsive design
Zero Dependencies - No external libraries, framework agnostic
🔧 TypeScript Ready - Full TypeScript definitions included

🚀 Quick Start

npm install @mil-rlib/reactjs-star-rating
import React, { useState } from 'react'
import StarRating from '@mil-rlib/reactjs-star-rating'

function App() {
  const [rating, setRating] = useState(3.5)

  return (
    <StarRating
      activeStars={rating}
      onStarsChange={setRating}
      allowHalf={true}
      totalStars={5}
    />
  )
}

✨ Key Features

🎯 Half-Star Precision

Click the left or right half of any star for precise 0.5 increment ratings

<StarRating allowHalf={true} precision={0.5} />

Ultra Performance

  • 889 bytes brotli compressed (75% smaller than v1.0)
  • Zero runtime dependencies
  • Tree-shakeable ES modules
  • Optimized React hooks with memoization

Accessibility First

  • ARIA labels and roles for screen readers
  • Semantic HTML structure
  • High contrast support
  • Focus indicators for better UX

🎨 Rich Customization

  • CSS-in-JS styling - no external stylesheets needed
  • Animation support with smooth transitions
  • Flexible theming with custom colors and sizes
  • Multiple interaction modes - interactive, read-only, disabled

📱 Mobile Optimized

  • Touch-friendly interactions
  • Responsive design works on all screen sizes
  • High DPI support for retina displays

📦 Installation

NPM:

npm install @mil-rlib/reactjs-star-rating

Yarn:

yarn add @mil-rlib/reactjs-star-rating

CDN (ES Modules):

<script type="module">
  import StarRating from 'https://unpkg.com/@mil-rlib/reactjs-star-rating/dist/index.js'
</script>

📖 Usage Guide

🔰 Basic Rating

Simple interactive star rating with click handling:

import React, { useState } from 'react'
import StarRating from '@mil-rlib/reactjs-star-rating'

function BasicRating() {
  const [rating, setRating] = useState(0)

  return (
    <div>
      <StarRating 
        activeStars={rating} 
        totalStars={5} 
        onClick={setRating} 
      />
      <p>Selected rating: {rating}</p>
    </div>
  )
}

⭐ Half-Star Precision

Enable half-star ratings by clicking left/right halves of stars:

function HalfStarRating() {
  const [rating, setRating] = useState(3.5)

  return (
    <StarRating
      activeStars={rating}
      totalStars={5}
      onClick={setRating}
      allowHalf={true}           // Enable half-star precision
      precision={0.5}            // 0.5 increment steps
      starStyle={{ fontSize: '32px', margin: '0 2px' }}
      activeStarStyle={{ color: '#ffa534' }}
      inActiveStarStyle={{ color: '#e0e0e0' }}
    />
  )
}

🎨 Custom Styling

Fully customize appearance with CSS-in-JS:

function CustomStyledRating() {
  const [rating, setRating] = useState(4)

  return (
    <StarRating
      activeStars={rating}
      onClick={setRating}
      totalStars={5}
      starStyle={{
        fontSize: '28px',
        margin: '0 4px',
        cursor: 'pointer',
        transition: 'all 0.2s ease',
      }}
      activeStarStyle={{
        color: '#ff4757',
        textShadow: '0 0 10px rgba(255,71,87,0.5)',
      }}
      inActiveStarStyle={{
        color: '#ddd',
        opacity: 0.7,
      }}
      containerStyle={{
        padding: '10px',
        backgroundColor: '#f8f9fa',
        borderRadius: '8px',
        display: 'inline-block',
      }}
    />
  )
}

🎭 Interactive Modes

Different interaction modes for various use cases:

function InteractionModes() {
  const [rating, setRating] = useState(4.5)

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: '20px' }}>

      {/* Interactive Mode - Full Control */}
      <div>
        <h4>Interactive (Default)</h4>
        <StarRating 
          activeStars={rating} 
          onClick={setRating}
          allowHalf={true}
          animate={true}
        />
      </div>

      {/* Read-Only Mode - Display Only */}
      <div>
        <h4>Read-Only Display</h4>
        <StarRating 
          activeStars={4.7} 
          readOnly={true}
          allowHalf={true}
          starStyle={{ color: '#ffc107' }}
        />
        <small>Perfect for showing average ratings</small>
      </div>

      {/* Disabled Mode - No Interactions */}
      <div>
        <h4>Disabled State</h4>
        <StarRating 
          activeStars={3} 
          disabled={true}
          starStyle={{ opacity: 0.5 }}
        />
      </div>

      {/* Clearable Mode - Click to Clear */}
      <div>
        <h4>Clearable Rating</h4>
        <StarRating 
          activeStars={rating} 
          onClick={setRating}
          clearable={true}
          onClear={() => setRating(0)}
        />
        <small>Click same rating to clear</small>
      </div>

    </div>
  )
}

🎬 Animations & Effects

Add smooth animations for better user experience:

function AnimatedRating() {
  const [rating, setRating] = useState(2.5)

  return (
    <StarRating
      activeStars={rating}
      onClick={setRating}
      allowHalf={true}
      animate={true}              // Enable scale animation
      starStyle={{
        fontSize: '36px',
        margin: '0 5px',
        transition: 'all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275)',
        cursor: 'pointer',
      }}
      activeStarStyle={{
        color: '#ff6b6b',
        filter: 'drop-shadow(0 0 8px rgba(255,107,107,0.4))',
      }}
      containerStyle={{
        padding: '20px',
      }}
    />
  )
}

📋 Complete API Reference

Core Props

Prop Type Default Description
activeStars number 0 Current rating value. Supports decimals for half-stars (e.g., 3.5). This is the displayed rating.
totalStars number 5 Total number of stars to display. Common values: 5, 10.
onClick (rating: number) => void () => {} Click handler - receives the new rating value when a star is clicked.
// Basic usage
<StarRating 
  activeStars={3.5} 
  totalStars={5} 
  onClick={(rating) => console.log('New rating:', rating)} 
/>

Precision & Half-Stars

Prop Type Default Description
allowHalf boolean false Enable half-star ratings. Users can click left/right halves of stars for 0.5 increments.
precision number 1 Rating step precision. Use 0.5 for half-stars, 1 for full stars only.
// Half-star precision example
<StarRating 
  activeStars={2.5}
  allowHalf={true}
  precision={0.5}        // Allows 0.5 increments: 1, 1.5, 2, 2.5, etc.
  onClick={setRating}
/>

Interaction Modes

Prop Type Default Description
readOnly boolean false Display-only mode. No interactions, perfect for showing average ratings or reviews.
disabled boolean false Disable all interactions. Stars become non-interactive and typically styled differently.
clearable boolean false Allow clearing rating. Clicking the same rating sets it to 0. Requires onClear or uses onClick(0).
onClear () => void undefined Clear callback. Called when rating is cleared. If not provided, falls back to onClick(0).
// Different interaction modes
<StarRating activeStars={4} readOnly={true} />              {/* Display only */}
<StarRating activeStars={4} disabled={true} />              {/* No interactions */}
<StarRating clearable={true} onClear={() => setRating(0)} /> {/* Clearable */}

Visual Customization

Prop Type Default Description
animate boolean false Enable hover animations. Stars scale smoothly on hover and click for better UX.
direction 'horizontal' | 'vertical' 'horizontal' Layout direction. Display stars horizontally or vertically.
// Animation and direction
<StarRating animate={true} direction="vertical" />

Styling Props (CSS-in-JS)

Prop Type Default Description
containerStyle CSSProperties {} Container element styles. Applied to the wrapper div containing all stars.
starStyle CSSProperties {} Base star styles. Applied to all star elements. Controls size, spacing, transitions.
activeStarStyle CSSProperties {} Active star styles. Applied to filled/active star portions. Controls color, effects.
inActiveStarStyle CSSProperties {} Inactive star styles. Applied to empty/inactive star portions.
// Complete styling example
<StarRating
  containerStyle={{
    padding: '16px',
    backgroundColor: '#f8f9fa',
    borderRadius: '12px',
    boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
  }}
  starStyle={{
    fontSize: '32px',
    margin: '0 4px',
    cursor: 'pointer',
    transition: 'all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275)',
  }}
  activeStarStyle={{
    color: '#ff6b35',
    textShadow: '0 0 8px rgba(255,107,53,0.4)',
    filter: 'drop-shadow(0 2px 4px rgba(255,107,53,0.3))',
  }}
  inActiveStarStyle={{
    color: '#e1e5e9',
    opacity: 0.8,
  }}
/>

Advanced Examples

E-commerce Product Rating:

function ProductRating({ averageRating, totalReviews }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
      <StarRating
        activeStars={averageRating}
        readOnly={true}
        allowHalf={true}
        starStyle={{ fontSize: '18px', color: '#ffc107' }}
      />
      <span style={{ color: '#666', fontSize: '14px' }}>
        ({totalReviews} reviews)
      </span>
    </div>
  )
}

// Usage
<ProductRating averageRating={4.3} totalReviews={127} />

User Review Form:

function ReviewForm() {
  const [rating, setRating] = useState(0)
  const [submitted, setSubmitted] = useState(false)

  const handleSubmit = () => {
    if (rating > 0) {
      // Submit review logic
      setSubmitted(true)
    }
  }

  return (
    <div>
      <h3>Rate this product:</h3>
      <StarRating
        activeStars={rating}
        onClick={setRating}
        allowHalf={true}
        clearable={true}
        animate={true}
        starStyle={{ fontSize: '28px', margin: '0 3px' }}
        activeStarStyle={{ color: '#4caf50' }}
        onClear={() => setRating(0)}
      />
      <p>Your rating: {rating || 'Not rated'}</p>
      <button 
        onClick={handleSubmit} 
        disabled={rating === 0}
        style={{ 
          marginTop: '16px',
          opacity: rating > 0 ? 1 : 0.5 
        }}
      >
        Submit Review
      </button>
    </div>
  )
}

⚡ Performance & Bundle Size

This component is meticulously optimized for performance:

📦 Ultra-Small Bundle

Build Output:
  889 B  - index.js.br     # 🎉 Brotli compressed (75% smaller!)
  1057 B - index.js.gz     # 🗜️ Gzip compressed  
  ~3.8KB - index.js        # 📦 Raw ES module

🚀 Performance Features

  • Zero runtime dependencies - No PropTypes, lodash, or external libs
  • Tree-shakeable ES modules - Only import what you need
  • Optimized React hooks - Uses useMemo and useCallback for minimal re-renders
  • Single-pass rendering - Efficient DOM updates with minimal operations
  • CSS-in-JS approach - No external stylesheets to load

📊 Benchmark Comparison

Library Bundle Size (Brotli) Dependencies Half-Stars TypeScript
@mil-rlib/reactjs-star-rating 889B 0
react-star-ratings 4.2KB 2
react-rating-stars-component 3.1KB 1
react-simple-star-rating 2.8KB 0

Accessibility Built-In

  • ARIA labels and roles for screen readers
  • Semantic HTML structure with proper roles
  • High contrast support for visually impaired users
  • Focus indicators (when not disabled/read-only)
  • Screen reader announcements for rating changes

🔄 Migration Guide

Upgrading from v1.x to v2.x

Good News: v2.x is 100% backward compatible with v1.x! All existing code continues to work without changes.

What's New in v2.x

  • Half-star precision with allowHalf and precision props
  • 75% smaller bundle - from 4.3KB to 889B brotli
  • Zero dependencies - removed PropTypes and other deps
  • Enhanced animations with animate prop
  • Clearable ratings with clearable and onClear props
  • Better accessibility with improved ARIA support
  • TypeScript definitions included out of the box

Breaking Changes

🎉 None! Your v1.x code works unchanged:

// ✅ v1.x code - works perfectly in v2.x
<StarRating activeStars={3} totalStars={5} onClick={setRating} />

1. Enable Half-Stars (Optional)

// Before (v1.x)
<StarRating activeStars={3} onClick={setRating} />

// After (v2.x) - Add half-star precision
<StarRating 
  activeStars={3.5}     // Now supports decimals!
  allowHalf={true}      // Enable half-star clicks
  onClick={setRating} 
/>

2. Add Animations (Optional)

// Before (v1.x)
<StarRating activeStars={rating} onClick={setRating} />

// After (v2.x) - Add smooth animations
<StarRating 
  activeStars={rating} 
  onClick={setRating}
  animate={true}        // Smooth hover/click animations
/>

3. Enhanced Styling (Optional)

// Before (v1.x) - Limited styling
<StarRating 
  activeStars={rating} 
  onClick={setRating}
  starStyle={{ color: 'gold' }}
/>

// After (v2.x) - Separate active/inactive styling
<StarRating 
  activeStars={rating} 
  onClick={setRating}
  starStyle={{ fontSize: '24px', margin: '0 2px' }}
  activeStarStyle={{ color: '#ffd700', textShadow: '0 0 5px gold' }}
  inActiveStarStyle={{ color: '#ddd', opacity: 0.6 }}
/>

4. Clearable Ratings (New Feature)

// New in v2.x - Allow users to clear their rating
<StarRating 
  activeStars={rating} 
  onClick={setRating}
  clearable={true}                    // Click same rating to clear
  onClear={() => setRating(0)}        // Optional clear callback
/>

Bundle Size Improvement

# v1.x Bundle Sizes
4.3KB - Brotli compressed
5.8KB - Gzip compressed  
18KB  - Raw bundle

# v2.x Bundle Sizes (75% smaller!)
889B  - Brotli compressed ⬇️ 
1057B - Gzip compressed  ⬇️
3.8KB - Raw bundle       ⬇️

TypeScript Users

v2.x includes built-in TypeScript definitions:

// No need for @types/ packages anymore!
import StarRating from '@mil-rlib/reactjs-star-rating'

interface RatingComponentProps {
  initialRating?: number
  onRatingChange: (rating: number) => void
}

const RatingComponent: React.FC<RatingComponentProps> = ({ 
  initialRating = 0, 
  onRatingChange 
}) => (
  <StarRating
    activeStars={initialRating}
    onClick={onRatingChange}
    allowHalf={true}          // TypeScript knows this is boolean
    precision={0.5}           // TypeScript knows this is number
  />
)

Performance Notes

  • Faster rendering - Optimized React hooks reduce re-renders
  • Smaller app bundles - 75% less code means faster page loads
  • No dependency conflicts - Zero runtime dependencies prevent version conflicts
  • Better tree-shaking - Modern ES modules work better with bundlers

🛠 Troubleshooting

Common Issues & Solutions

🔍 Stars Not Displaying

// Problem: Stars showing as squares or missing
// Solution: Ensure unicode star character is supported
<StarRating 
  activeStars={3}
  starStyle={{ 
    fontFamily: 'Arial, sans-serif',  // Fallback fonts
    fontSize: '24px'                  // Explicit size
  }}
/>

🌟 Half-Star Precision Issues

// Problem: Half-stars not working
// Solution: Enable both allowHalf and set precision
<StarRating 
  activeStars={3.5}
  allowHalf={true}        // ✅ Required for half-stars
  precision={0.5}         // ✅ Required for 0.5 increments
  onClick={setRating}
/>

// Problem: Unexpected decimal values
// Solution: Validate precision settings
const handleRating = (rating) => {
  // Round to nearest valid increment
  const roundedRating = Math.round(rating / 0.5) * 0.5
  setRating(roundedRating)
}

🎬 Animation Problems

// Problem: Animations not smooth or conflicting
// Solution: Check CSS conflicts and use proper styling
<StarRating 
  animate={true}
  starStyle={{ 
    transition: 'none',     // Clear conflicting transitions
    fontSize: '20px',
    margin: '0 2px'
  }}
  activeStarStyle={{ 
    color: '#ffd700' 
  }}
/>

// CSS to avoid conflicts
.star-rating-container * {
  transition: transform 0.2s ease !important;
}

⚡ Performance Issues

// Problem: Component re-rendering too often
// Solution: Memoize callback functions
import { useCallback, useState } from 'react'

const MyComponent = () => {
  const [rating, setRating] = useState(0)

  // ✅ Memoized callback prevents unnecessary re-renders
  const handleRatingChange = useCallback((newRating) => {
    setRating(newRating)
  }, [])

  return (
    <StarRating 
      activeStars={rating}
      onClick={handleRatingChange}  // Stable reference
    />
  )
}

🎨 Styling Problems

// Problem: Stars overlapping or misaligned
// Solution: Use proper container styling
<div style={{ 
  display: 'inline-flex',
  alignItems: 'center',
  gap: '2px'                    // Space between stars
}}>
  <StarRating 
    activeStars={rating}
    starStyle={{
      display: 'inline-block',  // Prevent layout issues
      lineHeight: 1,            // Consistent height
      verticalAlign: 'middle'   // Proper alignment
    }}
  />
</div>

// Problem: Half-star fills not showing
// Solution: Ensure proper positioning context
<StarRating 
  activeStars={2.5}
  allowHalf={true}
  starStyle={{
    position: 'relative',       // Required for overlay positioning
    fontSize: '24px'
  }}
/>

📱 Mobile Touch Issues

// Problem: Touch events not working on mobile
// Solution: Component handles touch automatically, but ensure proper viewport
<meta name="viewport" content="width=device-width, initial-scale=1.0">

// For custom mobile behavior
<StarRating 
  activeStars={rating}
  onClick={(rating, event) => {
    // Access original touch/click event if needed
    console.log('Touch/Click event:', event)
    setRating(rating)
  }}
/>

🔧 Bundle Size Issues

// Problem: Bundle size larger than expected
// Solution: Ensure proper tree-shaking

// ✅ Correct import (allows tree-shaking)
import StarRating from '@mil-rlib/reactjs-star-rating'

// ❌ Avoid this (imports everything)
import * as StarRatingLib from '@mil-rlib/reactjs-star-rating'

// Webpack Bundle Analyzer to verify
npm install --save-dev webpack-bundle-analyzer
npx webpack-bundle-analyzer build/static/js/*.js

⚠️ React Strict Mode Warnings

// Problem: Warnings in React development mode
// Solution: Component is Strict Mode compatible, but check for:

// 1. Stable key props in lists
{ratings.map((rating, index) => (
  <StarRating 
    key={`rating-${rating.id}`}  // Use stable ID, not index
    activeStars={rating.value}
  />
))}

// 2. Proper cleanup in effects
useEffect(() => {
  const handleResize = () => { /* resize logic */ }
  window.addEventListener('resize', handleResize)

  return () => window.removeEventListener('resize', handleResize)
}, [])

🌐 Server-Side Rendering (SSR)

// Problem: Hydration mismatches
// Solution: Handle SSR properly

// Next.js
import dynamic from 'next/dynamic'

const StarRating = dynamic(
  () => import('@mil-rlib/reactjs-star-rating'),
  { ssr: false }  // Disable SSR if needed
)

// Or handle hydration manually
const [isClient, setIsClient] = useState(false)

useEffect(() => {
  setIsClient(true)
}, [])

return (
  <div>
    {isClient ? (
      <StarRating activeStars={rating} onClick={setRating} />
    ) : (
      <div>Loading rating...</div>  // Placeholder
    )}
  </div>
)

Getting Help

License

This project is licensed under the MIT License - see the LICENSE file for details.\ MIT © milayek86

Issues

If you find any issues or have suggestions, please open an issue here.

changelog

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[2.0.0] - 2024-11-05

🚀 Major Performance Improvements

  • Bundle size reduced by 75%: 4.3KB → 889B brotli compressed
  • Zero runtime dependencies: Removed PropTypes and all external dependencies
  • Optimized re-renders: Added useMemo and useCallback for minimal re-renders
  • Better tree-shaking: Modern ES modules work better with bundlers
  • Performance benchmarks: Fastest React star rating component available

New Features

  • Half-star precision: Click left/right star halves for 0.5 increments with allowHalf prop
  • Flexible precision control: Set custom increment precision with precision prop
  • Smooth animations: Scale transitions on hover/click with animate prop
  • Clearable ratings: Click same rating to clear with clearable and onClear props
  • Enhanced accessibility: Complete ARIA support and screen reader compatibility
  • TypeScript definitions: Built-in TypeScript support with comprehensive prop types
  • Improved mobile experience: Better touch interaction and responsive design

🎨 Enhanced Styling

  • Separate active/inactive styling: Independent control with activeStarStyle and inActiveStarStyle
  • Better CSS-in-JS support: More granular styling options
  • Animation system: Smooth scale transitions with customizable timing
  • Overlay technique: Precise half-star fills using CSS positioning

Accessibility Improvements

  • ARIA labels and roles: Proper semantic structure for screen readers
  • Focus management: Improved keyboard navigation and focus indicators
  • Screen reader announcements: Clear feedback for rating changes
  • High contrast support: Better visibility for visually impaired users

🔧 Technical Improvements

  • Modern React Hooks: Complete rewrite using useState, useCallback, useMemo
  • ESM module format: Better compatibility with modern bundlers
  • Tree-shakeable exports: Import only what you need
  • Reduced API surface: Simplified props while maintaining functionality
  • Better error handling: Robust validation and fallback mechanisms

🔄 Migration Guide

Good News: v2.0.0 is 100% backward compatible with v1.x!

All existing v1.x code continues to work without changes:

// ✅ v1.x code works perfectly in v2.x
<StarRating activeStars={3} totalStars={5} onClick={setRating} />

New optional features to adopt:

// Enable half-star precision
<StarRating allowHalf={true} precision={0.5} />

// Add smooth animations  
<StarRating animate={true} />

// Allow clearing ratings
<StarRating clearable={true} onClear={() => setRating(0)} />

// Enhanced styling options
<StarRating 
  activeStarStyle={{ color: '#ffd700', textShadow: '0 0 5px gold' }}
  inActiveStarStyle={{ color: '#ddd', opacity: 0.6 }}
/>

📦 Bundle Size Comparison

# v1.x Bundle Sizes
4.3KB - Brotli compressed
5.8KB - Gzip compressed  
18KB  - Raw bundle

# v2.x Bundle Sizes (75% smaller!)
889B  - Brotli compressed ⬇️ 
1057B - Gzip compressed  ⬇️
3.8KB - Raw bundle       ⬇️

🛠 Breaking Changes

None! All v1.x props remain fully supported.

🐛 Bug Fixes

  • Fixed inconsistent hover states across different browsers
  • Improved click detection accuracy on star boundaries
  • Resolved layout shift issues during component mounting
  • Fixed accessibility warnings in React Strict Mode

[1.0.8] - 2024-10-15

Fixed

  • Minor styling improvements
  • Updated peer dependencies

[1.0.7] - 2024-09-20

Added

  • Basic star rating functionality
  • Click interaction support
  • Custom styling options

[1.0.0] - 2024-08-01

Added

  • Initial release
  • Basic React star rating component
  • NPM package setup