> ## Documentation Index
> Fetch the complete documentation index at: https://api.fanvue.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# RatingSummary

> An aggregated rating overview: a headline average with the total review count, followed by a per-rating histogram.

```tsx theme={null}
import { RatingSummary } from "@fanvue/ui";
import type { RatingCount, RatingSummaryProps } from "@fanvue/ui";
```

## Examples

## Default

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-ratingsummary--default&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="280" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="RatingSummary — Default" />
</Frame>

```tsx theme={null}
import { RatingSummary } from "@fanvue/ui";

<RatingSummary
  distribution={[
    { rating: 5, count: 300 },
    { rating: 4, count: 20 },
    { rating: 3, count: 20 },
    { rating: 2, count: 10 },
    { rating: 1, count: 0 },
  ]}
/>
```

## Empty

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-ratingsummary--empty&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="280" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="RatingSummary — Empty" />
</Frame>

```tsx theme={null}
import { RatingSummary } from "@fanvue/ui";

<RatingSummary
  distribution={[
    { rating: 5, count: 0 },
    { rating: 4, count: 0 },
    { rating: 3, count: 0 },
    { rating: 2, count: 0 },
    { rating: 1, count: 0 },
  ]}
/>
```

## Large Volume

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-ratingsummary--large-volume&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="280" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="RatingSummary — Large Volume" />
</Frame>

```tsx theme={null}
import { RatingSummary } from "@fanvue/ui";

<RatingSummary
  distribution={[
    { rating: 5, count: 18420 },
    { rating: 4, count: 7310 },
    { rating: 3, count: 1290 },
    { rating: 2, count: 540 },
    { rating: 1, count: 880 },
  ]}
/>
```

## Custom Average

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-ratingsummary--custom-average&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="280" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="RatingSummary — Custom Average" />
</Frame>

```tsx theme={null}
import { RatingSummary } from "@fanvue/ui";

<RatingSummary
  averageRating={4.3}
  distribution={[
    { rating: 5, count: 300 },
    { rating: 4, count: 20 },
    { rating: 3, count: 20 },
    { rating: 2, count: 10 },
    { rating: 1, count: 0 },
  ]}
/>
```

## Mixed

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-ratingsummary--mixed&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="280" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="RatingSummary — Mixed" />
</Frame>

```tsx theme={null}
import { RatingSummary } from "@fanvue/ui";

<RatingSummary
  distribution={[
    { rating: 5, count: 64 },
    { rating: 4, count: 81 },
    { rating: 3, count: 40 },
    { rating: 2, count: 18 },
    { rating: 1, count: 12 },
  ]}
/>
```

## Props

## RatingSummary

An aggregated rating overview: a headline average with the total review count, followed by a per-rating histogram. Bar lengths are scaled relative to the most-reviewed rating, so the busiest rating always fills the track.

The histogram is one shared grid (with subgrid rows) rather than per-row flex: the label column is sized by the widest label across all rows, so a width difference between labels (e.g. "1 review" vs "3 reviews") never changes a row's track length — every bar's right edge stays aligned.

The brand star is decorative; the header and each histogram row expose `role="img"` with an accessible label (override via `formatAverageLabel` / `formatRatingLabel`) so the single-star-plus-number reads clearly.

<ParamField path="distribution" type="RatingCount[]" required>
  Per-rating review counts. Order is not significant — rows always render from `maxRating` down to `1`, and any rating without an entry renders as zero. Entries are expected to use whole-number ratings within `1`–`maxRating`; any outside that range are ignored, including in the derived total and average.
</ParamField>

<ParamField path="averageRating" type="number">
  Average rating shown in the header. Defaults to the count-weighted mean of `distribution`; provide it to display a server-computed average instead.
</ParamField>

<ParamField path="formatAverageLabel" type="((average: string, maxRating: number, total: number) => string)" default={"(average, max, total) => `Average rating ${average} out of ${max}, ${formatCount(total)}`"}>
  Builds the accessible label for the header. Override to localise the screen-reader text. `average` is the already-formatted average string.
</ParamField>

<ParamField path="formatCount" type="((count: number) => string)" default={"(count) => `${count.toLocaleString()} review(s)`"}>
  Formats a review count into its label, without surrounding parentheses. Used for the visible text and as the count portion of the default accessible labels.
</ParamField>

<ParamField path="formatRatingLabel" type="((rating: number, count: number) => string)" default={"(rating, count) => `${rating} star(s), ${formatCount(count)}`"}>
  Builds the accessible label for each histogram row. Override to localise the screen-reader text.
</ParamField>

<ParamField path="maxRating" type="number" default="5">
  Highest possible rating. Sets how many histogram rows render.
</ParamField>

## Exported types

Also exported from `@fanvue/ui`: `RatingCount`, `RatingSummaryProps`.

***

**Setup:** [Installation](/docs/ui/installation) · [Theming](/docs/ui/theming)
