# Logo Cloud

> Customer logo strip of text wordmarks in varied weights and spacing, as an endless marquee or a bordered grid where each logo lifts to reveal a caption on hover.

A shadcn/ui block from the [@geturui](https://geturui.com/?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/geturui/logo-cloud).

- Page, with a live preview: https://shadcn.exchange/r/geturui/logo-cloud
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/geturui/logo-cloud-light-9c4786235d1f2a03.png
- Registry item: https://geturui.com/r/logo-cloud.json
- Categories: blocks, logos, customers, social proof, marquee, wordmark, trusted by
- Listed: 2026-10-23, source last changed 2026-10-23

## Install

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

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

## Dependencies

- Registry items: `@geturui/marquee`

## Files

### `registry/geturui/blocks/logo-cloud.tsx`

```tsx
import * as React from "react";
import { cn } from "@/lib/utils";
import { Marquee } from "@/components/ui/marquee";

export type WordmarkStyle = "geometric" | "mono" | "serif" | "heavy" | "light" | "rounded";
export type WordmarkGlyph = "dot" | "ring" | "square" | "slash" | "triangle" | "bars" | "none";

export interface Logo {
  name: string;
  /** Type treatment for the text wordmark. */
  style?: WordmarkStyle;
  /** Small drawn mark before the name. */
  glyph?: WordmarkGlyph;
  /** Grid variant: line revealed on hover, e.g. "Cut build time 38%". */
  caption?: string;
  href?: string;
}

export interface LogoCloudProps {
  /** Line above the logos. Pass null to hide. */
  heading?: string | null;
  logos?: Logo[];
  /** Infinite marquee, or a static grid that reveals a caption on hover. */
  variant?: "marquee" | "grid";
  /** Seconds per marquee loop. */
  duration?: number;
  className?: string;
}

const STYLE_CLASSES: Record<WordmarkStyle, string> = {
  geometric: "font-display text-[22px] font-semibold tracking-[-0.8px]",
  mono: "font-mono text-[15px] font-medium uppercase tracking-[0.22em]",
  serif: "font-serif text-[23px] italic tracking-[-0.3px]",
  heavy: "font-sans text-[21px] font-black uppercase tracking-[-1px]",
  light: "font-sans text-[22px] font-light tracking-[0.06em] lowercase",
  rounded: "font-display text-[21px] font-bold tracking-[-0.4px] lowercase",
};

function Glyph({ glyph }: { glyph: WordmarkGlyph }) {
  if (glyph === "none") return null;
  return (
    <svg aria-hidden viewBox="0 0 20 20" className="size-[18px] shrink-0" fill="none" stroke="currentColor" strokeWidth={2.2}>
      {glyph === "dot" && <circle cx="10" cy="10" r="6" fill="currentColor" stroke="none" />}
      {glyph === "ring" && (
        <>
          <circle cx="10" cy="10" r="7" />
          <circle cx="10" cy="10" r="2.5" fill="currentColor" stroke="none" />
        </>
      )}
      {glyph === "square" && <rect x="3.5" y="3.5" width="13" height="13" rx="3.5" transform="rotate(45 10 10)" />}
      {glyph === "slash" && <path d="M5 17 L15 3 M10 17 L18 6" strokeLinecap="round" />}
      {glyph === "triangle" && <path d="M10 3 L17.5 16.5 H2.5 Z" fill="currentColor" stroke="none" />}
      {glyph === "bars" && <path d="M4 16V9 M10 16V4 M16 16v-5" strokeLinecap="round" strokeWidth={3} />}
    </svg>
  );
}

/** A made-up company rendered as a text wordmark. */
export function Wordmark({ logo, className }: { logo: Logo; className?: string }) {
  return (
    <span className={cn("inline-flex items-center gap-2 whitespace-nowrap leading-none", STYLE_CLASSES[logo.style ?? "geometric"], className)}>
      <Glyph glyph={logo.glyph ?? "none"} />
      {logo.name}
    </span>
  );
}

const DEFAULT_LOGOS: Logo[] = [
  { name: "Halcyon", style: "geometric", glyph: "ring", caption: "Rebuilt onboarding in a week" },
  { name: "quillfire", style: "rounded", glyph: "slash", caption: "62 components in production" },
  { name: "Orbital/9", style: "mono", glyph: "none", caption: "Docs bounce rate down 24%" },
  { name: "Mosswood", style: "serif", glyph: "dot", caption: "One design system, four apps" },
  { name: "KESTREL", style: "heavy", glyph: "triangle", caption: "Shipped dark mode in a day" },
  { name: "lumenstack", style: "light", glyph: "bars", caption: "Checkout conversion up 11%" },
  { name: "Tidewave", style: "geometric", glyph: "square", caption: "Replaced 3 animation libraries" },
  { name: "Vellum", style: "serif", glyph: "none", caption: "Pricing page shipped in 2 hours" },
];

/** Strip of text-wordmark logos: an endless marquee, or a bordered grid where each cell lifts its logo and reveals a caption on hover. */
export function LogoCloud({
  heading = "Trusted by product teams at fast-moving companies",
  logos = DEFAULT_LOGOS,
  variant = "marquee",
  duration = 36,
  className,
}: LogoCloudProps) {
  return (
    <section className={cn("@container w-full px-4 py-12 sm:px-6 sm:py-16", className)}>
      <div className="mx-auto grid max-w-6xl gap-8">
        {heading && <p className="text-balance text-center text-sm font-medium text-ink-subtle">{heading}</p>}
        {variant === "marquee" ? (
          <Marquee duration={duration} className="py-2">
            {logos.map((l) => (
              <span key={l.name} className="mx-6 inline-flex items-center text-ink-muted transition-colors duration-200 hover:text-ink @xl:mx-8">
                <Wordmark logo={l} />
              </span>
            ))}
          </Marquee>
        ) : (
          <ul className="grid grid-cols-2 gap-px overflow-hidden rounded-lg border border-border bg-border @xl:grid-cols-4">
            {logos.map((l) => {
              const inner = (
                <>
                  <span className="text-ink-muted transition-[transform,color] duration-500 ease-[var(--ease-spring)] group-hover/logo:-translate-y-2.5 group-hover/logo:text-ink group-focus-visible/logo:-translate-y-2.5 group-focus-visible/logo:text-ink">
                    <Wordmark logo={l} />
                  </span>
                  {l.caption && (
                    <span className="absolute inset-x-3 bottom-5 translate-y-2 text-center text-[12px] font-medium text-volt-ink opacity-0 blur-[4px] transition-[transform,opacity,filter] duration-500 ease-[var(--ease-spring)] group-hover/logo:translate-y-0 group-hover/logo:opacity-100 group-hover/logo:blur-0 group-focus-visible/logo:translate-y-0 group-focus-visible/logo:opacity-100 group-focus-visible/logo:blur-0">
                      {l.caption}
                    </span>
                  )}
                </>
              );
              const cell =
                "group/logo relative flex h-28 items-center justify-center bg-surface px-4 outline-none transition-colors duration-200 hover:bg-surface-raised focus-visible:bg-surface-raised focus-visible:shadow-[inset_0_0_0_2px_var(--volt-ink)] @xl:h-32";
              return (
                <li key={l.name} className="contents">
                  {l.href ? (
                    <a href={l.href} className={cell}>
                      {inner}
                    </a>
                  ) : (
                    <div className={cell} tabIndex={l.caption ? 0 : undefined}>
                      {inner}
                    </div>
                  )}
                </li>
              );
            })}
          </ul>
        )}
      </div>
    </section>
  );
}
```

### `LICENSE-geturui.md`

```md
MIT License

Copyright (c) 2026 geturui.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
