1 GitHub star = 1 new component.

Star the repo
Logos & Partners

Logo Wall Grid

Static customer logo wall with hairline dividers; text wordmarks by default or real logo images.

logoscustomerssocial-proofgrid
Live Preview

Powering 12,000+ teams, from startups to the Fortune 500

  • Northwind
  • Lumen
  • Orbitly
  • Civic
  • Driftly
  • Acme
  • Helix
  • Nimbus

Usage

Copy and paste this code into your React component:

tsx
import { LogoWallGrid } from 'react-component-kit-ui/sections';

<LogoWallGrid columns={4} logos={[{ name: 'Acme' }, { name: 'Globex', src: '/logos/globex.svg' }]} />

Manual Installation

If you are not using the npm package, create a new file and paste the following code: src/components/sections/LogoWallGrid.tsx + LogoWallGrid.css:

LogoWallGrid.tsx
'use client';

import type { CSSProperties } from 'react';
import './LogoWallGrid.css';

/** "a: b; --c: d" โ†’ style object */
function st(css: string | undefined): CSSProperties {
  const o: Record<string, string> = {};
  for (const decl of String(css ?? '').split(';')) {
    const i = decl.indexOf(':');
    if (i < 0) continue;
    const k = decl.slice(0, i).trim();
    if (k) o[k.startsWith('--') ? k : k.replace(/-([a-z])/g, (_, c) => c.toUpperCase())] = decl.slice(i + 1).trim();
  }
  return o as CSSProperties;
}

interface Logo { name: string; src?: string; href?: string }

/**
 * LogoWallGrid โ€” Static grid of customer wordmarks with hairline dividers and
 * an optional headline stat. Logos render as text wordmarks by default; pass
 * image URLs to use real logos.
 *
 * @param {string} title - Small heading above the grid.
 * @param {Array<{name: string, src?: string, href?: string}>} logos - Customers.
 * @param {number} columns - Columns on desktop (3|4|6).
 * @param {string} variant - Grid style (divided|cards|plain).
 * @param {string} size - Vertical rhythm (sm|md|lg).
 * @param {string} className - Extra CSS class.
 */
export interface LogoWallGridProps {
  title?: string;
  logos?: Logo[];
  columns?: 3 | 4 | 6;
  variant?: 'divided' | 'cards' | 'plain';
  size?: 'sm' | 'md' | 'lg';
  className?: string;
}

export function LogoWallGrid({
  title = 'Powering 12,000+ teams, from startups to the Fortune 500',
  logos = [
    { name: 'Northwind' }, { name: 'Lumen' }, { name: 'Orbitly' }, { name: 'Civic' },
    { name: 'Driftly' }, { name: 'Acme' }, { name: 'Helix' }, { name: 'Nimbus' },
  ],
  columns = 4,
  variant = 'divided',
  size = 'md',
  className = '',
}: LogoWallGridProps) {
  const id = `lwg-${Math.random().toString(36).slice(2, 8)}`;
  const glyphs = [
    '<circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="3.5" fill="currentColor"/>',
    '<path d="M12 3 21 20H3z"/>',
    '<rect x="4" y="4" width="16" height="16" rx="4"/><path d="M4 12h16"/>',
    '<path d="M4 18 12 4l8 14M8 12h8"/>',
  ];
  return (
    <>
      <div className="cq-logo-wall-grid-cq" data-rk-c72122="">
      <section className={`lwg lwg--${variant} lwg--${size} ${className}`} aria-labelledby={id} style={st(`--lwg-cols:${columns}`)} data-rk-c72122="">
        <div className="lwg__inner" data-rk-c72122="">
          <h2 id={id} className="lwg__title" data-rk-c72122="">{title}</h2>
          <ul className="lwg__grid" data-rk-c72122="">
            {logos.map((l, i) => {
              const inner = l.src
                ? <img src={l.src} alt={l.name} loading="lazy" decoding="async" data-rk-c72122="" />
                : (
                  <span className="lwg__word" data-rk-c72122="">
                    <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinejoin="round" aria-hidden="true" dangerouslySetInnerHTML={{ __html: glyphs[i % glyphs.length] }} data-rk-c72122=""></svg>
                    {l.name}
                  </span>
                );
              return (
                <li className="lwg__cell" data-rk-c72122="">
                  {l.href ? <a href={l.href} className="lwg__link" data-rk-c72122="">{inner}</a> : inner}
                </li>
              );
            })}
          </ul>
        </div>
      </section>
      </div>
    </>
  );
}

export default LogoWallGrid;
LogoWallGrid.css
/* LogoWallGrid โ€” ported from astro-component-kit (sections/LogoWallGrid.astro) */

.cq-logo-wall-grid-cq:where([data-rk-c72122]) { container-type: inline-size; }
.lwg:where([data-rk-c72122]) {
  --lwg-py: 4.5rem;
  padding: var(--lwg-py) var(--sp-6, 1.5rem);
  background: var(--c-bg, #050505);
}
.lwg--sm:where([data-rk-c72122]) { --lwg-py: 3rem; }
.lwg--lg:where([data-rk-c72122]) { --lwg-py: 6.5rem; }
.lwg__inner:where([data-rk-c72122]) { max-width: 1120px; margin: 0 auto; }
.lwg__title:where([data-rk-c72122]) { margin: 0 auto 2.5rem; max-width: 560px; text-align: center; font-size: 1rem; font-weight: 550; line-height: 1.5; color: var(--c-text-2, #a3a3a3); text-wrap: balance; }
.lwg__grid:where([data-rk-c72122]) { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(var(--lwg-cols), minmax(0, 1fr)); }
.lwg--divided:where([data-rk-c72122]) .lwg__grid:where([data-rk-c72122]) { gap: 1px; background: rgb(var(--ink-rgb, 255 255 255) / 0.07); border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.07); border-radius: var(--r-lg, 20px); overflow: hidden; }
.lwg--cards:where([data-rk-c72122]) .lwg__grid:where([data-rk-c72122]) { gap: 0.75rem; }
.lwg__cell:where([data-rk-c72122]) { display: grid; place-items: center; min-height: 112px; padding: 1.25rem; background: var(--c-bg, #050505); }
.lwg--cards:where([data-rk-c72122]) .lwg__cell:where([data-rk-c72122]) { border-radius: var(--r-md, 14px); background: rgb(var(--ink-rgb, 255 255 255) / 0.025); border: 1px solid var(--c-border, rgb(var(--ink-rgb, 255 255 255) / 0.07)); }
.lwg--plain:where([data-rk-c72122]) .lwg__cell:where([data-rk-c72122]) { background: transparent; }
.lwg__word:where([data-rk-c72122]) { display: inline-flex; align-items: center; gap: 0.5rem; font-size: 1.25rem; font-weight: 750; letter-spacing: -0.03em; color: var(--c-text-2, #a3a3a3); transition: color 0.25s ease; }
.lwg__cell:hover:where([data-rk-c72122]) .lwg__word:where([data-rk-c72122]) { color: var(--c-text-1, #fff); }
.lwg__cell:where([data-rk-c72122]) img:where([data-rk-c72122]) { max-width: 140px; max-height: 40px; object-fit: contain; filter: grayscale(1) brightness(1.6); opacity: 0.75; transition: opacity 0.25s ease, filter 0.25s ease; }
.lwg__cell:hover:where([data-rk-c72122]) img:where([data-rk-c72122]) { opacity: 1; filter: none; }
.lwg__link:where([data-rk-c72122]) { display: grid; place-items: center; width: 100%; height: 100%; min-height: 44px; text-decoration: none; border-radius: 8px; }
.lwg__link:focus-visible:where([data-rk-c72122]) { outline: 2px solid var(--c-primary-light, #d4a017); outline-offset: 2px; }
@container (max-width: 760px) { .lwg__grid:where([data-rk-c72122]) { grid-template-columns: repeat(2, minmax(0, 1fr)); } }