Rating row
Stars, average, review count and one short verified quote under the title, linking to the reviews section.
componentratinganyreviews
$
npx shadcn@latest add @storekit/pdp-rating-rowpdp-rating-row
Live and interactive. Switch the brand in the frame header to see the same source under another token file.
Installation
$
npx shadcn@latest add @storekit/pdp-rating-row$
pnpm dlx shadcn@latest add @storekit/pdp-rating-row$
yarn dlx shadcn@latest add @storekit/pdp-rating-row$
bunx --bun shadcn@latest add @storekit/pdp-rating-rowSource
components/storekit/pdp/pdp-rating-row.tsx
65 lines
"use client"
import { BadgeCheck } from "lucide-react"
import { cn } from "@/components/storekit/lib/cn"
import { Stars } from "@/components/storekit/ui/stars"
import { useSkBlock } from "@/components/storekit/lib/sk-analytics"
/* Above-the-fold social proof that sits under the product title: stars,
average, review count and one short verified quote. The whole row links
to the reviews section so the proof is one tap from the full evidence. */
type Quote = { text: string; author: string; verified?: boolean }
export function PdpRatingRow({
rating = 4.8,
count = 1284,
quote = { text: "Mixes clean, tastes great, and I actually look forward to it.", author: "Dana R.", verified: true },
href = "#reviews",
className,
}: {
rating?: number
count?: number
quote?: Quote | null
/** Anchor or URL of the full reviews section. */
href?: string
className?: string
}) {
const sk = useSkBlock("pdp", "pdp-rating-row")
const jump = (label: string) => sk.emit("interact", label, undefined)
return (
<div {...sk.attrs} ref={sk.ref as React.RefObject<HTMLDivElement>} className={cn("flex w-full flex-col gap-1.5", className)}>
<a
href={href}
onClick={() => jump("reviews_jump")}
aria-label={`Rated ${rating.toFixed(1)} out of 5 from ${count.toLocaleString("en-US")} reviews. Read reviews`}
className="group/rr -mx-1 inline-flex min-h-[44px] w-fit flex-wrap items-center gap-x-2 gap-y-1 rounded-sk-btn px-1 outline-none transition-transform duration-200 ease-sk-out focus-visible:ring-2 focus-visible:ring-sk-accent focus-visible:ring-offset-2 focus-visible:ring-offset-sk-paper active:scale-[0.97]"
>
<Stars value={rating} size={15} />
<span className="text-sm font-semibold tabular-nums text-sk-ink">{rating.toFixed(1)}</span>
<span aria-hidden className="h-3 w-px bg-sk-line" />
<span className="text-sm tabular-nums text-sk-muted underline decoration-sk-line underline-offset-4 transition-colors duration-200 group-hover/rr:text-sk-ink group-hover/rr:decoration-sk-ink/40">
{count.toLocaleString("en-US")} reviews
</span>
</a>
{quote ? (
<figure className="flex min-w-0 flex-wrap items-baseline gap-x-2 gap-y-0.5 text-sm leading-[1.5]">
<blockquote className="min-w-0 text-sk-ink">
<p>“{quote.text}”</p>
</blockquote>
<figcaption className="inline-flex items-center gap-1 text-[13px] text-sk-muted">
{quote.author}
{quote.verified ? (
<>
<BadgeCheck size={13} aria-hidden className="text-sk-savings" />
<span className="sr-only">, verified buyer</span>
</>
) : null}
</figcaption>
</figure>
) : null}
</div>
)
}
Usage
Import from "@/components/storekit/pdp/pdp-rating-row" and pass your product data. The demo above exercises the full prop surface with sample values.