---
title: ContentReview
description: A review score from a provider — its icon in an outlined chip, the rating and a label
---

```tsx
import { ContentReview } from '@/ui/ContentReview';

export function ContentReviewDemo() {
  return (
    <div className="flex flex-col gap-16">
      <ContentReview label="1975 reviews" providerIcon="GoogleMonogram" rating="4.5/5" />
      <ContentReview providerIcon="GoogleMonogram" rating="4.5/5" />
    </div>
  );
}
```

## Installation

Using the CLI:

```bash
npx shadcn@latest add https://develop.trident-ui.pro.clubmed/r/content-review.json
```

Or manually, copy the following code into `/ui/ContentReview.tsx`:

```tsx
import type { IconicNames } from '@clubmed/trident-icons';
import type { ComponentPropsWithoutRef, FunctionComponent } from 'react';

import { Chip } from './Chip';
import { Image } from './Image';
import { cn } from './helpers/cn';

export interface ContentReviewProps extends Omit<ComponentPropsWithoutRef<'span'>, 'children'> {
  /**
   * Text displayed after the rating, like a number of reviews
   */
  label?: string;
  /**
   * Icon of the review provider, displayed in an outlined chip
   */
  providerIcon: IconicNames;
  /**
   * Rating, displayed as text
   */
  rating: string;
  /**
   * URL of an image illustrating the rating, like the provider's rating bubbles
   */
  ratingImage?: string;
}

export const ContentReview: FunctionComponent<ContentReviewProps> = ({
  className,
  label,
  providerIcon,
  rating,
  ratingImage,
  ...attrs
}) => {
  return (
    <span {...attrs} className={cn('flex items-center gap-x-8', className)}>
      <Chip color="lightGrey" icon={providerIcon} iconWidth="16px" size="size-32" theme="outline" />
      {/* The rating is already in the text below: the image is decorative. */}
      {ratingImage && <Image alt="" className="-mx-8" src={ratingImage} />}
      <span className="truncate">
        {rating}
        {label && (
          <span className="@max-[100px]/product-thumbnail-content-review:sr-only"> • {label}</span>
        )}
      </span>
    </span>
  );
};
```

## Usage

```tsx showLineNumbers
import { ContentReview } from '@/ui/ContentReview';

export function Component() {
  return <ContentReview label="1975 reviews" providerIcon="GoogleMonogram" rating="4.5/5" />;
}
```

The rating and the label are joined with a bullet (`4.5/5 • 1975 reviews`). Without a label, only the rating is displayed.

### With a rating image

Some providers have their own rating visual, like TripAdvisor's bubbles. Pass its URL as `ratingImage` to display it between the chip and the text.

```tsx
import { ContentReview } from '@/ui/ContentReview';

export function ContentReviewRatingImageDemo() {
  return (
    <ContentReview
      className="text-b3"
      label="812 reviews"
      providerIcon="TripAdvisorMonogram"
      rating="4.5/5"
      ratingImage="https://www.tripadvisor.fr/img/cdsi/img2/ratings/traveler/s4.5-24206-5.svg"
    />
  );
}
```

```tsx showLineNumbers
<ContentReview
  label="812 reviews"
  providerIcon="TripAdvisorMonogram"
  rating="4.5/5"
  ratingImage="https://www.tripadvisor.fr/img/cdsi/img2/ratings/traveler/s4.5-24206-5.svg"
/>
```

## API Reference

### ContentReview

Extra props are spread on the root `<span>`.

| Prop           | Type          | Default     | Description                                                         |
| -------------- | ------------- | ----------- | ------------------------------------------------------------------- |
| `providerIcon` | `IconicNames` | (required)  | Icon of the review provider, displayed in an outlined grey chip.    |
| `rating`       | `string`      | (required)  | Rating, displayed as text. Format it yourself (`4.5/5`, `9/10`…).   |
| `label`        | `string`      | `undefined` | Text displayed after the rating, like a number of reviews.          |
| `ratingImage`  | `string`      | `undefined` | URL of an image illustrating the rating, displayed before the text. |
| `className`    | `string`      | `undefined` | Classes merged on the root, e.g. to change the font size.           |

## Accessibility

- The rating image is **decorative** (`alt=""`): the rating is already in the text, so a screen reader announces it once.
- The provider icon has no accessible name. If the provider matters, say it in the `label` (`1975 Google reviews`) or give the root a `title`.

## Notes

- **Truncation**: the text truncates with an ellipsis when the review is constrained in width; the chip and the image never shrink.
- **Font size**: the component sets none, so it inherits the font size of its parent. Pass a text class (`text-b3`, `text-b4`) to set it.
- **Performance**: the rating image is rendered with `Image`, so it is lazy loaded and decoded asynchronously.
