# Social-Proof-Companies-4

> A social proof section that showcases brand logos in a marquee layout

A shadcn/ui block from the [@hexui](https://hexui.sh) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/hexui/social-proof-companies-4).

- Page, with a live preview: https://shadcn.exchange/r/hexui/social-proof-companies-4
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/hexui/social-proof-companies-4-light-1929919514b364b3.png
- Registry item: https://hexui.sh/r/social-proof-companies-4.json
- Categories: social-proof
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://hexui.sh/r/social-proof-companies-4.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Files

### `registry/blocks/social-proof/social-proof-companies-4/source/app/social-proof/page.tsx`

```tsx
import { SocialProof } from "../../components/social-proof"

export default function Page() {
    return (
        <SocialProof />
    )
}
```

### `registry/blocks/social-proof/social-proof-companies-4/source/components/social-proof.tsx`

```tsx
import Image from "next/image";
import { Marquee } from '@/components/ui/marquee';

// Logos registry
const logos = [
    { src: "/demo/logos/cursor.svg", alt: "Cursor logo" },
    { src: "/demo/logos/discord.svg", alt: "Discord logo" },
    { src: "/demo/logos/framer.svg", alt: "Framer logo" },
    { src: "/demo/logos/github.svg", alt: "Github logo" },
    { src: "/demo/logos/google.svg", alt: "Google logo" },
    { src: "/demo/logos/tailwind.svg", alt: "Tailwind logo" },
    { src: "/demo/logos/linear.svg", alt: "Linear logo" },
    { src: "/demo/logos/netflix.svg", alt: "Netflix logo" },
    { src: "/demo/logos/openai.svg", alt: "OpenAI logo" },
    { src: "/demo/logos/polar.svg", alt: "Polar logo" },
    { src: "/demo/logos/notion.svg", alt: "Notion logo" },
    { src: "/demo/logos/resend.svg", alt: "Resend logo" },
    { src: "/demo/logos/shopify.svg", alt: "Shopify logo" },
    { src: "/demo/logos/spotify.svg", alt: "Spotify logo" },
    { src: "/demo/logos/supabase.svg", alt: "Supabase logo" },
    { src: "/demo/logos/vercel.svg", alt: "Vercel logo" },
];

export function SocialProof() {
    return (
        <div className="mx-auto flex min-h-dvh w-full max-w-sm flex-col justify-center gap-8 px-4 py-12 md:max-w-3xl">
            {/* Description */}
            <div className="flex flex-col">
                <p className="text-center text-sm md:text-base text-muted-foreground">LOGO MARQUEE</p>
                <p className="text-center text-xs md:text-sm text-muted-foreground">Some logos are for illustrative purposes only.</p>
            </div>

            {/* Logos */}
            {/* Logos scroll in a seamless marquee. `unoptimized` bypasses the Next image optimizer. */}
            <Marquee className="w-full">
                {logos.map((logo) => (
                    <Image
                        key={logo.src}
                        src={logo.src}
                        alt={logo.alt}
                        width={96}
                        height={96}
                        loading="eager"
                        className="mx-4 md:mx-8 h-6 md:h-12 w-24 md:w-30 object-contain opacity-80 not-dark:invert-100 pointer-events-none select-none"
                        unoptimized
                    />
                ))}
            </Marquee>
        </div>
    )
}
```

### `registry/components/marquee.tsx`

```tsx
import { type ComponentPropsWithoutRef } from "react"

import { cn } from "@/lib/utils"

interface MarqueeProps extends ComponentPropsWithoutRef<"div"> {
  /**
   * Optional CSS class name to apply custom styles
   */
  className?: string
  /**
   * Whether to reverse the animation direction
   * @default false
   */
  reverse?: boolean
  /**
   * Whether to pause the animation on hover
   * @default false
   */
  pauseOnHover?: boolean
  /**
   * Content to be displayed in the marquee
   */
  children: React.ReactNode
  /**
   * Whether to animate vertically instead of horizontally
   * @default false
   */
  vertical?: boolean
  /**
   * Number of times to repeat the content
   * @default 4
   */
  repeat?: number
}

export function Marquee({
  className,
  reverse = false,
  pauseOnHover = false,
  children,
  vertical = false,
  repeat = 4,
  style,
  ...props
}: MarqueeProps) {
  // Edge-fade mask applied via CSS mask-image so content fades out at both ends.
  const fadeMask = vertical
    ? "linear-gradient(to bottom, transparent 0%, black 12%, black 88%, transparent 100%)"
    : "linear-gradient(to right, transparent 0%, black 12%, black 88%, transparent 100%)"

  return (
    <div
      {...props}
      style={{
        ...style,
        maskImage: fadeMask,
        WebkitMaskImage: fadeMask,
      }}
      className={cn(
        "group relative flex gap-(--gap) overflow-hidden [--duration:40s] [--gap:12px]",
        vertical ? "flex-col" : "flex-row",
        className
      )}
    >
      {/* Duplicate children N times so the marquee loops seamlessly without a visible gap. */}
      {Array.from({ length: repeat }).map((_, i) => (
        <div
          key={i}
          className={cn(
            "flex shrink-0 justify-around gap-(--gap) motion-reduce:animate-none",
            vertical
              ? "animate-marquee-vertical flex-col"
              : "animate-marquee flex-row",
            reverse && "direction-[reverse]",
            pauseOnHover && "group-hover:paused"
          )}
        >
          {children}
        </div>
      ))}
    </div>
  )
}
```
