Logo cloud
A static grid of customer marks on hairlines that rise from muted to full ink on hover.
npx shadcn@latest add https://ui.goodtabs.co/r/logo-cloud.json
With the @goodtabs namespace in components.json: npx shadcn@latest add @goodtabs/logo-cloud
Trusted by small teams
- Northwind
- Halcyon
- Quarry
- Tidemark
- Lumen & Co
- Parallel
- Okra
- Ferrous
Eight made-up wordmarks on a hairline grid.
Five wide
- Northwind
- Halcyon
- Quarry
- Tidemark
- Lumen & Co
- Parallel
- Okra
- Ferrous
- Mosaic Labs
- Vesper
Ten marks across five columns.
Usage
import { LogoCloud } from "@/components/logo-cloud"
<LogoCloud title="Trusted by small teams" logos={[{ name: "Northwind", mark: <span>Northwind</span> }]} />Props
| Prop | Type | Default | Description |
|---|---|---|---|
| title | string | Small mono line above the grid. | |
| logos | { name: string; mark: ReactNode }[] | Each mark is an SVG or styled text. The name is read by screen readers. | |
| columns | 3 | 4 | 5 | 4 | Columns from sm up; two on a phone. |
Source
logo-cloud/logo-cloud.tsx
import * as React from "react";
import { cn } from "@/lib/utils";
export type Logo = {
/** Company name, read by screen readers. */
name: string;
/** The mark: an inline SVG or styled text. Decorative, so it is hidden from assistive tech. */
mark: React.ReactNode;
};
type LogoCloudProps = Omit<React.ComponentProps<"section">, "title"> & {
/** Small line above the grid. */
title?: string;
logos: Logo[];
/** Columns from the sm breakpoint up. Two on a phone. */
columns?: 3 | 4 | 5;
};
const cols = {
3: "sm:grid-cols-3",
4: "sm:grid-cols-4",
5: "sm:grid-cols-5",
};
/**
* A static grid of customer marks separated by hairlines. Marks are muted and
* rise to full ink on hover. Server component.
*/
export function LogoCloud({ title, logos, columns = 4, className, ...props }: LogoCloudProps) {
return (
<section data-slot="logo-cloud" className={cn("w-full px-6 py-10 md:px-8", className)} {...props}>
<div className="mx-auto flex max-w-6xl flex-col gap-6">
{title && (
<p className="m-0 text-center font-mono text-xs tracking-wide text-muted-foreground uppercase">{title}</p>
)}
<ul
className={cn(
"m-0 grid list-none grid-cols-2 gap-px overflow-hidden rounded-lg border bg-border p-0",
cols[columns],
)}
>
{logos.map((logo) => (
<li
key={logo.name}
className="grid h-20 place-items-center bg-background px-4 text-muted-foreground transition-colors duration-150 ease-out hover:text-foreground"
>
<span className="sr-only">{logo.name}</span>
<span aria-hidden className="flex items-center gap-2">
{logo.mark}
</span>
</li>
))}
</ul>
</div>
</section>
);
}
For AI agents
Hand your agent this page, the markdown at /components/logo-cloud/prompt.md, or the Copy AI prompt button above.
When to use
- Social proof under a hero
- When you have six or more recognisable customers
When not to use
- With one or two customers, where a quote is stronger
- With a scrolling marquee; this one is static
Agent notes
- Server component; marks are decorative and hidden from assistive tech, name is in sr-only
- Pass currentColor marks so they follow the muted and hover tones
- Use only logos you have permission to show; the demos use invented names