Surfaces
Logo grid
A grid of logos around a centre cell with a heading, for integrations or partners.
Adapted from Watermelon UI (MIT) and rewritten with keyboard support, labels and reduced motion.
Preview
Usage
logo-grid-demo.tsx
import { BarChart3, Bell, Calendar, Cloud, CreditCard, Database, FileText, Mail, MessageSquare, Package, ShoppingCart, Truck } from 'lucide-react'
import { LogoGrid } from '@/components/logo-grid'
const ITEMS = [
{ name: 'Mail', logo: <Mail /> },
{ name: 'Calendar', logo: <Calendar /> },
{ name: 'Payments', logo: <CreditCard /> },
{ name: 'Shipping', logo: <Truck /> },
{ name: 'Inventory', logo: <Package /> },
{ name: 'Chat', logo: <MessageSquare /> },
{ name: 'Database', logo: <Database /> },
{ name: 'Storage', logo: <Cloud /> },
{ name: 'Analytics', logo: <BarChart3 /> },
{ name: 'Checkout', logo: <ShoppingCart /> },
{ name: 'Invoices', logo: <FileText /> },
{ name: 'Alerts', logo: <Bell /> },
]
export default function LogoGridDemo() {
return (
<LogoGrid
items={ITEMS}
title="Works with the tools you already use"
description="Connect your shop to payments, shipping and stock in a few clicks."
action={
<a href="#integrations" className="inline-flex min-h-11 items-center rounded-full bg-foreground px-5 text-sm font-medium text-background">
See all integrations
</a>
}
/>
)
}Source
logo-grid.tsx
// Based on Watermelon UI's “Integrations 2” block (MIT, © 2026 Watermelon Platform Contributors,
// github.com/WatermelonCorp/watermelon-platform). Rewritten with any logos, a phone layout and theme tokens.
import type { ReactNode } from 'react'
import { cn } from '@/lib/utils'
export type LogoGridItem = { name: string; logo: ReactNode }
export type LogoGridProps = {
/** Twelve fill the grid around the centre; fewer leave empty cells. */
items: LogoGridItem[]
title: ReactNode
description?: ReactNode
/** E.g. a link to all integrations. */
action?: ReactNode
className?: string
}
/**
* A grid of logos around a centre cell with a heading, for integrations or partners.
* On a phone the heading comes first and the logos fall in two columns below.
*/
export function LogoGrid({ items, title, description, action, className }: LogoGridProps) {
return (
<section className={cn('grid grid-cols-2 border-t border-l sm:grid-cols-4', className)}>
<div className="relative isolate col-span-2 flex flex-col items-center justify-center gap-3 overflow-hidden border-r border-b px-6 py-10 text-center sm:col-start-2 sm:row-span-2 sm:row-start-2">
{/* Thin diagonal lines behind the text. */}
<span aria-hidden className="absolute inset-0 -z-10 bg-[repeating-linear-gradient(135deg,var(--color-border)_0_1px,transparent_1px_10px)] opacity-60" />
<h2 className="text-2xl font-semibold tracking-tight text-balance">{title}</h2>
{description && <p className="max-w-xs text-sm text-pretty text-muted-foreground">{description}</p>}
{action}
</div>
<ul className="contents">
{items.map((item) => (
<li key={item.name} className="group flex aspect-square flex-col items-center justify-center gap-2 border-r border-b p-4 sm:aspect-auto sm:min-h-32">
<span className="grid size-10 place-items-center text-muted-foreground transition-colors duration-200 group-hover:text-foreground [&_svg]:size-7">{item.logo}</span>
<span className="text-xs text-muted-foreground">{item.name}</span>
</li>
))}
</ul>
</section>
)
}Install
npx shadcn@latest add https://mikkelmanniche.dk/lab/r/logo-grid.jsonWith the registry added (components.json)
npx shadcn@latest add @manniche/logo-grid