Reviews

Reviews

What our customers say

4.8 4.8 out of 5, based on 1,284 reviews

  • 5 stars82%82%
  • 4 stars12%12%
  • 3 stars4%4%
  • 2 stars1%1%
  • 1 stars1%1%
  • Rated 5 out of 5

    Finally, CSS that scales

    We moved three products to Spruce. The tokens keep everything consistent.

    Leo Novak · Frontend Lead Verified on G2
  • Rated 5 out of 5

    Beautiful defaults

    The design styles saved us weeks of theming work for our white-label clients.

    Sara Kim · Agency Owner Verified on Capterra
  • Rated 4 out of 5

    Great docs

    The documentation answers every question. The AI skills are a nice touch.

    Omar Haddad · Developer Verified on Product Hunt
  • Rated 5 out of 5

    Accessible out of the box

    Focus states, RTL and reduced motion are handled. Our audit was a breeze.

    Ava Martinez · Accessibility Specialist Verified on G2
  • Rated 5 out of 5

    Small and fast

    Our CSS bundle got smaller after the migration, not bigger.

    Daniel Okafor · Engineer Verified on Capterra
  • Rated 4 out of 5

    Lovely components

    The blocks are a great starting point for landing pages.

    Maya Chen · Designer Verified on Product Hunt
@use 'sprucecss/scss/spruce' as *;

$reviews-star: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="m12 2 3.1 6.3 6.9 1-5 4.9 1.2 6.8L12 17.8 5.8 21l1.2-6.8-5-4.9 6.9-1z"/></svg>';

.reviews-block {
  padding-block: spacer-clamp('xl', 'xxl');

  &__inner {
    display: grid;
    gap: spacer-clamp('l', 'xl');

    @include breakpoint('lg') {
      grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
    }
  }

  &__summary {
    align-self: start;
    @include layout-stack('m');

    @include breakpoint('lg') {
      inset-block-start: spacer('l');
      position: sticky;
    }
  }

  &__average {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: spacer('xs') spacer('s');

    strong {
      color: color('heading');
      font-family: config('font-family-heading', $typography);
      font-size: font-size('h1');
      line-height: 1;
    }

    span:last-child {
      color: color('muted');
      font-size: config('font-size-sm', $typography);
      inline-size: 100%;
    }
  }

  // Five stars from one element: a star-shaped mask over a two-color fill, so partial ratings (4.8) work too.
  &__stars {
    --direction: to right;
    --rating: 0;
    --size: 1.1rem;
    background-image: linear-gradient(var(--direction), #{color('warning', 'alert')} calc(var(--rating) / 5 * 100%), #{color('border-strong')} 0);
    block-size: var(--size);
    display: inline-block;
    flex-shrink: 0;
    inline-size: calc(var(--size) * 5);
    mask: url('#{svg-escape($reviews-star)}') 0 0 / var(--size) var(--size) repeat-x;
    vertical-align: middle;
  }

  &__distribution {
    font-size: config('font-size-sm', $typography);
    list-style: none;
    padding: 0;
    @include layout-stack('xxs');

    li {
      align-items: center;
      display: grid;
      gap: spacer('xs');
      grid-template-columns: 4rem 1fr 2.5rem;
    }

    meter {
      block-size: 0.5rem;
    }

    span:last-child {
      color: color('muted');
      text-align: end;
    }
  }

  &__grid {
    @include clear-list;
    @include layout-grid('m', 16rem);

    // The items sit side by side: clear the stack margins of the base list style.
    > li {
      margin-block: 0;
      padding-block: 0;
    }
  }

  &__card {
    article {
      background-color: color('surface');
      block-size: 100%;
      border: config('border-width-base', $display) solid color('border');
      border-radius: radius('lg');
      display: flex;
      flex-direction: column;
      gap: spacer('xs');
      padding: spacer('m');
    }
  }

  &__rating {
    margin: 0;
  }

  // The card is a flex column (the text grows), so its text children drop the browser margins.
  &__title {
    font-size: font-size('h5');
    margin-block: 0;
  }

  &__text {
    color: color('text');
    flex-grow: 1;
    margin-block: 0;
  }

  &__footer {
    align-items: center;
    border-block-start: config('border-width-base', $display) solid color('border');
    display: flex;
    flex-wrap: wrap;
    font-size: config('font-size-sm', $typography);
    gap: spacer('xs');
    justify-content: space-between;
    padding-block-start: spacer('s');
  }
}

[dir='rtl'] .reviews-block__stars {
  --direction: to left;
}
<section class="reviews-block" aria-labelledby="reviews-title">
    <div class="container">
        <div class="reviews-block__inner">
            <div class="reviews-block__summary">
            <header class="block-heading block-heading--start">
                <p class="block-heading__eyebrow">Reviews</p>
                <h2 class="block-heading__title" id="reviews-title">What our customers say</h2>
            </header>
                <p class="reviews-block__average">
                    <strong>4.8</strong>
                    <span class="reviews-block__stars" style="--rating: 4.8;" aria-hidden="true"></span>
                    <span>4.8 out of 5, based on 1,284 reviews</span>
                </p>
                <ul class="reviews-block__distribution" role="list" aria-label="Rating distribution">
                    <li>
                        <span>5 stars</span>
                        <meter min="0" max="100" value="82" aria-label="5 stars: 82%">82%</meter>
                        <span>82%</span>
                    </li>
                    <li>
                        <span>4 stars</span>
                        <meter min="0" max="100" value="12" aria-label="4 stars: 12%">12%</meter>
                        <span>12%</span>
                    </li>
                    <li>
                        <span>3 stars</span>
                        <meter min="0" max="100" value="4" aria-label="3 stars: 4%">4%</meter>
                        <span>4%</span>
                    </li>
                    <li>
                        <span>2 stars</span>
                        <meter min="0" max="100" value="1" aria-label="2 stars: 1%">1%</meter>
                        <span>1%</span>
                    </li>
                    <li>
                        <span>1 stars</span>
                        <meter min="0" max="100" value="1" aria-label="1 stars: 1%">1%</meter>
                        <span>1%</span>
                    </li>
                </ul>
            </div>
            <ul class="reviews-block__grid" role="list">
                <li class="reviews-block__card">
                    <article>
                        <p class="reviews-block__rating"><span class="reviews-block__stars" style="--rating: 5;" aria-hidden="true"></span><span class="sr-only">Rated 5 out of 5</span></p>
                        <h3 class="reviews-block__title">Finally, CSS that scales</h3>
                        <p class="reviews-block__text">We moved three products to Spruce. The tokens keep everything consistent.</p>
                        <footer class="reviews-block__footer">
                            <span><strong>Leo Novak</strong> · Frontend Lead</span>
                            <span class="badge badge--success">Verified on G2</span>
                        </footer>
                    </article>
                </li>
                <li class="reviews-block__card">
                    <article>
                        <p class="reviews-block__rating"><span class="reviews-block__stars" style="--rating: 5;" aria-hidden="true"></span><span class="sr-only">Rated 5 out of 5</span></p>
                        <h3 class="reviews-block__title">Beautiful defaults</h3>
                        <p class="reviews-block__text">The design styles saved us weeks of theming work for our white-label clients.</p>
                        <footer class="reviews-block__footer">
                            <span><strong>Sara Kim</strong> · Agency Owner</span>
                            <span class="badge badge--success">Verified on Capterra</span>
                        </footer>
                    </article>
                </li>
                <li class="reviews-block__card">
                    <article>
                        <p class="reviews-block__rating"><span class="reviews-block__stars" style="--rating: 4;" aria-hidden="true"></span><span class="sr-only">Rated 4 out of 5</span></p>
                        <h3 class="reviews-block__title">Great docs</h3>
                        <p class="reviews-block__text">The documentation answers every question. The AI skills are a nice touch.</p>
                        <footer class="reviews-block__footer">
                            <span><strong>Omar Haddad</strong> · Developer</span>
                            <span class="badge badge--success">Verified on Product Hunt</span>
                        </footer>
                    </article>
                </li>
                <li class="reviews-block__card">
                    <article>
                        <p class="reviews-block__rating"><span class="reviews-block__stars" style="--rating: 5;" aria-hidden="true"></span><span class="sr-only">Rated 5 out of 5</span></p>
                        <h3 class="reviews-block__title">Accessible out of the box</h3>
                        <p class="reviews-block__text">Focus states, RTL and reduced motion are handled. Our audit was a breeze.</p>
                        <footer class="reviews-block__footer">
                            <span><strong>Ava Martinez</strong> · Accessibility Specialist</span>
                            <span class="badge badge--success">Verified on G2</span>
                        </footer>
                    </article>
                </li>
                <li class="reviews-block__card">
                    <article>
                        <p class="reviews-block__rating"><span class="reviews-block__stars" style="--rating: 5;" aria-hidden="true"></span><span class="sr-only">Rated 5 out of 5</span></p>
                        <h3 class="reviews-block__title">Small and fast</h3>
                        <p class="reviews-block__text">Our CSS bundle got smaller after the migration, not bigger.</p>
                        <footer class="reviews-block__footer">
                            <span><strong>Daniel Okafor</strong> · Engineer</span>
                            <span class="badge badge--success">Verified on Capterra</span>
                        </footer>
                    </article>
                </li>
                <li class="reviews-block__card">
                    <article>
                        <p class="reviews-block__rating"><span class="reviews-block__stars" style="--rating: 4;" aria-hidden="true"></span><span class="sr-only">Rated 4 out of 5</span></p>
                        <h3 class="reviews-block__title">Lovely components</h3>
                        <p class="reviews-block__text">The blocks are a great starting point for landing pages.</p>
                        <footer class="reviews-block__footer">
                            <span><strong>Maya Chen</strong> · Designer</span>
                            <span class="badge badge--success">Verified on Product Hunt</span>
                        </footer>
                    </article>
                </li>
            </ul>
        </div>
    </div>
</section>

Reviews

On this page

A review wall with the average rating, a rating distribution and verified review cards.

Technical Details

  • The distribution uses native meter elements (styled by Spruce CSS) with an aria-label per row; the percentages are also visible as text.
  • The stars are decorative; the rating is in a visually hidden text ("Rated 5 out of 5"). The fill is a mask driven by --rating, so fractional ratings work, and it mirrors in RTL.
  • The summary column is sticky on large screens.
  • It combines the Badge component for the "Verified" label.
  • Override the content with reviewsBlock.

Documentation

Learn about Spruce CSS through our extensive documentation.

Components

Explore our UI library of accessible components built with Spruce CSS.

Blocks and Pages

Full-width page blocks and complete page templates, ready to copy.

Find us on GitHub

Did you find a bug? Have an idea or a question? Please open an issue to help us develop the project.