# Logo Cloud

> Customer logo wall as an infinite marquee or a static grid.

- Author: Atelier UI
- License: MIT
- Page: https://chromotion.dev/en/components/logo-cloud
- Site: Atelier UI (https://chromotion.dev)

## Install

```bash
npx shadcn@latest add https://chromotion.dev/r/logo-cloud.json
```

Stack: React + TypeScript + Tailwind CSS v4, shadcn/ui conventions. `cn` comes from `@/lib/utils`.

## Dependencies

No extra dependencies.

## Usage

```tsx title="components/logo-cloud-demo.tsx"
import { Command, Feather, Hexagon, Layers, Mountain, Orbit, Triangle, Zap } from "lucide-react"

import { LogoCloud } from "@/components/logo-cloud"

const logos = [
  { name: "Hexa", icon: Hexagon },
  { name: "Vertex", icon: Triangle },
  { name: "Boltshift", icon: Zap },
  { name: "Layerstack", icon: Layers },
  { name: "Keystone", icon: Command },
  { name: "Quill", icon: Feather },
  { name: "Summit", icon: Mountain },
  { name: "Orbital", icon: Orbit },
]

export default function LogoCloudDemo() {
  return (
    <div className="flex w-full max-w-4xl flex-col gap-16">
      <LogoCloud logos={logos} title="Trusted by fast-moving teams worldwide" />
      <LogoCloud logos={logos} variant="grid" />
    </div>
  )
}
```

## Source

```tsx title="components/logo-cloud.tsx"
import * as React from "react"

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

const keyframes = `@keyframes logo-cloud-x{from{transform:translateX(0)}to{transform:translateX(calc(-50% - var(--gap)/2))}}`

export type Logo = {
  name: string
  icon?: React.ComponentType<{ className?: string }>
}

export interface LogoCloudProps extends Omit<React.ComponentProps<"div">, "title"> {
  logos: Logo[]
  title?: React.ReactNode
  /** "marquee" scrolls the logos, "grid" lays them out statically */
  variant?: "marquee" | "grid"
  /** Seconds for one full loop of the marquee */
  duration?: number
  pauseOnHover?: boolean
  /** Logos stay muted until hovered */
  muted?: boolean
}

function LogoItem({ logo, muted }: { logo: Logo; muted: boolean }) {
  const Icon = logo.icon
  return (
    <div
      className={cn(
        "flex shrink-0 items-center gap-2 text-lg font-semibold tracking-tight whitespace-nowrap transition-colors",
        muted ? "text-muted-foreground hover:text-foreground" : "text-foreground"
      )}
    >
      {Icon && <Icon className="size-6" />}
      {logo.name}
    </div>
  )
}

export function LogoCloud({
  logos,
  title,
  variant = "marquee",
  duration = 30,
  pauseOnHover = true,
  muted = true,
  className,
  ...props
}: LogoCloudProps) {
  return (
    <div className={cn("flex w-full flex-col items-center gap-8", className)} {...props}>
      {title && <p className="text-sm font-medium text-muted-foreground">{title}</p>}
      {variant === "grid" ? (
        <div className="grid w-full grid-cols-2 place-items-center gap-x-8 gap-y-10 sm:grid-cols-3 lg:grid-cols-4">
          {logos.map((logo) => (
            <LogoItem key={logo.name} logo={logo} muted={muted} />
          ))}
        </div>
      ) : (
        <div
          className="group flex w-full overflow-hidden [--gap:3.5rem] [mask-image:linear-gradient(to_right,transparent,black_12%,black_88%,transparent)]"
          style={{ gap: "var(--gap)" }}
        >
          <style href="logo-cloud" precedence="default">
            {keyframes}
          </style>
          {[0, 1].map((copy) => (
            <div
              key={copy}
              aria-hidden={copy === 1}
              className={cn(
                "flex shrink-0 items-center motion-reduce:[animation-play-state:paused]",
                pauseOnHover && "group-hover:[animation-play-state:paused]"
              )}
              style={{
                gap: "var(--gap)",
                animationName: "logo-cloud-x",
                animationDuration: `${duration}s`,
                animationTimingFunction: "linear",
                animationIterationCount: "infinite",
              }}
            >
              {logos.map((logo) => (
                <LogoItem key={logo.name} logo={logo} muted={muted} />
              ))}
            </div>
          ))}
        </div>
      )}
    </div>
  )
}
```
