Skip to main content

Rating

The Rating component displays a visual star rating, typically used to show product ratings, review scores, or user satisfaction levels. The current implementation is read-only.

Installation

npm install @naturacosmeticos/natds-web

Usage

import { Rating } from '@naturacosmeticos/natds-web';

function ProductRating() {
  return <Rating rate={4} size="small" />;
}

Rating Sizes

Small (Default)

Compact rating for inline display:
<Rating rate={3.5} size="small" />

Standard

Standard size for general use:
<Rating rate={4} size="standard" />

Semi

Larger rating for emphasis:
<Rating rate={5} size="semi" />

SemiX

Extra large for high visibility:
<Rating rate={4.5} size="semix" />

Product Card Example

import { Card, CardContent, Typography, Rating } from '@naturacosmeticos/natds-web';

function ProductCard({ product }) {
  return (
    <Card>
      <CardContent>
        <img src={product.image} alt={product.name} style={{ width: '100%' }} />
        <Typography variant="h6">{product.name}</Typography>
        <Typography variant="body2" color="textSecondary">
          {product.description}
        </Typography>
        
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 8 }}>
          <Rating rate={product.rating} size="small" />
          <Typography variant="body2" color="textSecondary">
            ({product.reviewCount} reviews)
          </Typography>
        </div>
        
        <Typography variant="h6" style={{ marginTop: 8 }}>
          ${product.price}
        </Typography>
      </CardContent>
    </Card>
  );
}

Review List Example

function ReviewList({ reviews }) {
  return (
    <div>
      {reviews.map((review) => (
        <div key={review.id} style={{ marginBottom: 24, padding: 16, border: '1px solid #e0e0e0' }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 8 }}>
            <div>
              <Typography variant="subtitle1">{review.author}</Typography>
              <Typography variant="caption" color="textSecondary">
                {review.date}
              </Typography>
            </div>
            <Rating rate={review.rating} size="small" />
          </div>
          
          <Typography variant="h6" style={{ marginBottom: 8 }}>
            {review.title}
          </Typography>
          
          <Typography variant="body2">
            {review.comment}
          </Typography>
        </div>
      ))}
    </div>
  );
}

Rating Summary

function RatingSummary({ ratings }) {
  const totalRatings = ratings.reduce((sum, r) => sum + r.count, 0);
  const averageRating = ratings.reduce((sum, r) => sum + (r.stars * r.count), 0) / totalRatings;

  return (
    <div style={{ padding: 24 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 16, marginBottom: 24 }}>
        <div>
          <Typography variant="h3">{averageRating.toFixed(1)}</Typography>
          <Rating rate={averageRating} size="standard" />
          <Typography variant="body2" color="textSecondary">
            {totalRatings} ratings
          </Typography>
        </div>
      </div>

      {[5, 4, 3, 2, 1].map((stars) => {
        const rating = ratings.find(r => r.stars === stars) || { count: 0 };
        const percentage = (rating.count / totalRatings) * 100;

        return (
          <div key={stars} style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8 }}>
            <Typography variant="body2" style={{ width: 30 }}>
              {stars}
            </Typography>
            <div style={{ 
              flex: 1, 
              height: 8, 
              backgroundColor: '#e0e0e0', 
              borderRadius: 4 
            }}>
              <div style={{ 
                width: `${percentage}%`, 
                height: '100%', 
                backgroundColor: '#ffa000',
                borderRadius: 4
              }} />
            </div>
            <Typography variant="body2" style={{ width: 50 }}>
              {rating.count}
            </Typography>
          </div>
        );
      })}
    </div>
  );
}

Different Rating Values

function RatingExamples() {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
      <div>
        <Typography variant="body2">No rating (0 stars)</Typography>
        <Rating rate={0} />
      </div>
      
      <div>
        <Typography variant="body2">Low rating (1.5 stars)</Typography>
        <Rating rate={1.5} />
      </div>
      
      <div>
        <Typography variant="body2">Average rating (3 stars)</Typography>
        <Rating rate={3} />
      </div>
      
      <div>
        <Typography variant="body2">Good rating (4 stars)</Typography>
        <Rating rate={4} />
      </div>
      
      <div>
        <Typography variant="body2">Perfect rating (5 stars)</Typography>
        <Rating rate={5} />
      </div>
    </div>
  );
}

With Text Labels

function LabeledRating({ rate }) {
  const getRatingLabel = (rating) => {
    if (rating >= 4.5) return 'Excellent';
    if (rating >= 3.5) return 'Good';
    if (rating >= 2.5) return 'Average';
    if (rating >= 1.5) return 'Poor';
    return 'Very Poor';
  };

  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
      <Rating rate={rate} size="small" />
      <Typography variant="body2">
        {rate.toFixed(1)} - {getRatingLabel(rate)}
      </Typography>
    </div>
  );
}

Product Comparison

function ProductComparison({ products }) {
  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 16 }}>
      {products.map((product) => (
        <Card key={product.id}>
          <CardContent>
            <img src={product.image} alt={product.name} style={{ width: '100%' }} />
            <Typography variant="h6">{product.name}</Typography>
            
            <div style={{ margin: '8px 0' }}>
              <Rating rate={product.rating} size="standard" />
            </div>
            
            <Typography variant="body2" color="textSecondary">
              {product.rating} ({product.reviews} reviews)
            </Typography>
            
            <Typography variant="h6" style={{ marginTop: 8 }}>
              ${product.price}
            </Typography>
          </CardContent>
        </Card>
      ))}
    </div>
  );
}

Props

rate
number
The rating value to display (0-5). Supports decimal values for partial stars.
size
'small' | 'standard' | 'semi' | 'semix'
default:"'small'"
The size of the rating stars.
id
string
The input id property for the component.
className
string
CSS class name to apply to the component.
style
React.CSSProperties
Inline styles to apply to the component.

Component Behavior

  • The Rating component is read-only and cannot be interacted with
  • Displays exactly 5 stars
  • Supports decimal values for partial star fills
  • Uses the Natura icon set for star icons
  • Automatically handles star fill based on the rate prop

Best Practices

  • Use consistent sizing across similar contexts (e.g., all product cards)
  • Always display the numeric rating alongside the stars for clarity
  • Include the number of reviews/ratings to provide context
  • Use small size for compact layouts and lists
  • Use larger sizes for emphasis on detail pages
  • Consider showing 0 stars vs hiding the rating when there are no reviews
  • Round displayed numbers appropriately (e.g., 4.67 → 4.7)

Accessibility

  • The component renders read-only rating visualization
  • Always pair with text that states the numeric rating
  • Include review count for context
  • Ensure sufficient color contrast for star icons
  • Consider adding aria-label for screen readers (e.g., “Rated 4 out of 5 stars”)

Common Patterns

Rating with Count

<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
  <Rating rate={4.3} size="small" />
  <Typography variant="body2">4.3 (127)</Typography>
</div>

Rating in List Item

<ListItem>
  <ListItemText 
    primary="Product Name"
    secondary={
      <>
        <Rating rate={4.5} size="small" />
        <span style={{ marginLeft: 8 }}>4.5 stars</span>
      </>
    }
  />
</ListItem>

Styling

The Rating component uses design tokens from the Natura design system for consistent styling. The star icons automatically adapt to your theme’s color palette.
  • Icon - Used internally for star icons
  • Typography - For rating labels and counts

Build docs developers (and LLMs) love