Proof-led hero

Oversized average rating and review count lead, with a pinned featured review, award chips and press quotes as text wordmarks.

blockproofanyctatrust
$npx shadcn@latest add @storekit/hero-proof
hero-proof

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/hero-proof
$pnpm dlx shadcn@latest add @storekit/hero-proof
$yarn dlx shadcn@latest add @storekit/hero-proof
$bunx --bun shadcn@latest add @storekit/hero-proof

Source

components/storekit/hero/hero-proof.tsx
164 lines
"use client"

import { motion, useReducedMotion } from "motion/react"
import { Award, BadgeCheck } from "lucide-react"
import { cn } from "@/components/storekit/lib/cn"
import { useSkBlock } from "@/components/storekit/lib/sk-analytics"
import { Stars } from "@/components/storekit/ui/stars"

/* Proof-led hero. The evidence is the headline: an oversized average
   rating with stars and the verified review count, a featured review pinned
   to the product image, award chips and a row of press quotes set as
   wordmarks. The rating links to the reviews section. Publications render
   as text so no third-party logos ship with the block; pass `logo` images
   if you have the rights. Stacks proof first on mobile, then the image. */

const EASE = [0.23, 1, 0.32, 1] as const

type Cta = { label: string; href: string }
export type PressQuote = { outlet: string; quote: string; logo?: string; href?: string }

const PRIMARY =
  "sk-btn inline-flex min-h-12 items-center justify-center py-2.5 text-center leading-tight rounded-sk-btn bg-sk-accent px-7 text-[15px] font-medium text-sk-accent-ink outline-none transition-[filter,transform] duration-200 ease-sk-out hover:brightness-[1.06] focus-visible:ring-2 focus-visible:ring-sk-accent focus-visible:ring-offset-2 focus-visible:ring-offset-sk-paper active:scale-[0.97]"

const PRESS: PressQuote[] = [
  { outlet: "The Daily Edit", quote: "The greens powder that finally tastes good." },
  { outlet: "Wellness Weekly", quote: "Best electrolyte of the year." },
  { outlet: "Morning Report", quote: "A routine you will actually keep." },
]

export function HeroProof({
  rating = 4.8,
  count = 12400,
  reviewsHref = "#reviews",
  headline = "Loved by 12,400 verified customers.",
  subcopy = "Every review is from a confirmed order. Read the good, the bad and the photos.",
  primaryCta = { label: "Shop best sellers", href: "#" },
  awards = ["Best Greens 2026", "Clean Label Certified"],
  press = PRESS,
  review = { quote: "I have tried six greens powders. This is the only one I have reordered four times.", author: "Priya S.", verified: true },
  image = "/placeholder.webp",
  imageAlt = "",
  className,
}: {
  rating?: number
  count?: number
  reviewsHref?: string
  headline?: string
  subcopy?: string
  primaryCta?: Cta
  awards?: string[]
  press?: PressQuote[]
  review?: { quote: string; author: string; verified?: boolean } | null
  image?: string
  imageAlt?: string
  className?: string
}) {
  const reduce = useReducedMotion()
  const sk = useSkBlock("hero", "hero-proof")
  const rise = (i: number) => ({
    initial: { opacity: 0, y: reduce ? 0 : 8 },
    animate: { opacity: 1, y: 0 },
    transition: { duration: 0.5, ease: EASE, delay: reduce ? 0 : i * 0.07 },
  })

  return (
    <section ref={sk.ref} {...sk.attrs} className={cn("bg-sk-paper text-sk-ink", className)}>
      <div className="mx-auto w-full max-w-6xl px-4 py-10 sm:px-8 sm:py-14">
        <div className="grid items-center gap-10 lg:grid-cols-[1.1fr_0.9fr] lg:gap-14">
          <div>
            <motion.a
              {...rise(0)}
              href={reviewsHref}
              onClick={() => sk.emit("interact", "rating")}
              aria-label={`Rated ${rating.toFixed(1)} out of 5 from ${count.toLocaleString("en-US")} reviews. Read reviews.`}
              className="group inline-flex flex-wrap items-end gap-x-4 gap-y-2 rounded-sk-card outline-none focus-visible:ring-2 focus-visible:ring-sk-accent focus-visible:ring-offset-4 focus-visible:ring-offset-sk-paper"
            >
              <span aria-hidden className="font-sk-display font-semibold leading-[0.85] tracking-[-0.05em] tabular-nums" style={{ fontSize: "clamp(4.5rem, 12vw, 8.5rem)" }}>
                {rating.toFixed(1)}
              </span>
              <span aria-hidden className="mb-2 flex flex-col gap-1.5">
                <Stars value={rating} size={20} />
                <span className="text-sm text-sk-muted underline decoration-sk-line underline-offset-4 transition-[text-decoration-color] group-hover:decoration-sk-ink">
                  {count.toLocaleString("en-US")} verified reviews
                </span>
              </span>
            </motion.a>
            <motion.h1 {...rise(1)} className="mt-6 max-w-xl text-balance font-sk-display font-semibold leading-[1.1] tracking-[-0.02em]" style={{ fontSize: "clamp(1.6rem, 3vw, 2.4rem)" }}>
              {headline}
            </motion.h1>
            <motion.p {...rise(2)} className="mt-3 max-w-md text-[15px] leading-[1.55] text-sk-muted">
              {subcopy}
            </motion.p>
            <motion.div {...rise(3)} className="mt-7 flex flex-col gap-4 sm:flex-row sm:items-center">
              <a href={primaryCta.href} onClick={() => sk.emit("interact", "cta")} className={PRIMARY}>
                {primaryCta.label}
              </a>
              {awards.length ? (
                <ul className="flex flex-wrap gap-2">
                  {awards.map((a) => (
                    <li key={a} className="inline-flex items-center gap-1.5 rounded-sk-chip border border-sk-line px-3 py-1.5 text-[12px] font-medium">
                      <Award size={14} aria-hidden className="text-sk-accent" />
                      {a}
                    </li>
                  ))}
                </ul>
              ) : null}
            </motion.div>
          </div>

          <motion.div
            initial={{ opacity: 0, scale: reduce ? 1 : 0.97 }}
            animate={{ opacity: 1, scale: 1 }}
            transition={{ duration: 0.6, ease: EASE, delay: reduce ? 0 : 0.1 }}
            className="relative pb-16 sm:pb-12"
          >
            <div className="relative aspect-[4/3] overflow-hidden rounded-sk-card border border-sk-line bg-sk-surface lg:aspect-[4/5]">
              <img src={image} alt={imageAlt} className="absolute inset-0 h-full w-full object-cover" />
            </div>
            {review ? (
              <motion.figure
                initial={{ opacity: 0, y: reduce ? 0 : 14 }}
                animate={{ opacity: 1, y: 0 }}
                transition={{ type: "spring", stiffness: 220, damping: 26, delay: reduce ? 0 : 0.35 }}
                className="absolute bottom-0 left-3 right-3 rounded-sk-card border border-sk-line bg-sk-card p-4 shadow-[0_30px_60px_-30px_rgb(var(--sk-ink)/0.45)] sm:left-auto sm:right-[-12px] sm:w-[300px] lg:-left-10 lg:right-auto"
              >
                <Stars value={5} size={13} />
                <blockquote className="mt-2 text-[14px] leading-[1.45]">{review.quote}</blockquote>
                <figcaption className="mt-2.5 flex items-center gap-1.5 text-[12px] text-sk-muted">
                  <span className="font-medium text-sk-ink">{review.author}</span>
                  {review.verified ? (
                    <>
                      <BadgeCheck size={13} aria-hidden className="text-sk-savings" />
                      Verified buyer
                    </>
                  ) : null}
                </figcaption>
              </motion.figure>
            ) : null}
          </motion.div>
        </div>

        {press.length ? (
          <motion.ul {...rise(4)} aria-label="As seen in" className="mt-10 grid gap-px overflow-hidden rounded-sk-card border border-sk-line bg-sk-line sm:grid-cols-3">
            {press.slice(0, 3).map((p) => (
              <li key={p.outlet} className="bg-sk-paper px-5 py-4">
                <figure>
                  <blockquote className="text-[14px] leading-[1.45] text-sk-ink">&ldquo;{p.quote}&rdquo;</blockquote>
                  <figcaption className="mt-2">
                    {p.logo ? (
                      <img src={p.logo} alt={p.outlet} className="h-5 w-auto opacity-70" />
                    ) : (
                      <span className="font-sk-display text-[15px] font-semibold uppercase tracking-[0.08em] text-sk-muted">{p.outlet}</span>
                    )}
                  </figcaption>
                </figure>
              </li>
            ))}
          </motion.ul>
        ) : null}
      </div>
    </section>
  )
}

Usage

Only use real ratings, awards and press quotes you can cite.