A tiny React library that makes logos look good together.
Real-world logos are messy. Some have padding, some don't. Some are dense and blocky, others are thin and airy. Put them in a row and they look chaotic.
React Logo Soup fixes this automatically.
Read the full deep-dive: The Logo Soup Problem (and how to solve it)
npm install react-logo-soupimport { LogoSoup } from "react-logo-soup";
function LogoStrip() {
return (
<LogoSoup
logos={[
{ src: "/logos/acme.svg", alt: "Acme Corp" },
{ src: "/logos/globex.svg", alt: "Globex" },
{ src: "/logos/initech.svg", alt: "Initech" },
]}
/>
);
}That's it! React Logo Soup will analyze each logo and normalize them to look visually balanced.
Logos can be plain URL strings or objects with alt text. Use objects to provide accessible alt text for each logo. The alt text is passed directly to the underlying <img> tag.
Space between logos. Default is 16.
<LogoSoup logos={logos} gap={24} />How big the logos should be, in pixels. Default is 48.
<LogoSoup logos={logos} baseSize={64} />React Logo Soup measures the "visual weight" of each logo. Dense, solid logos get scaled down. Light, thin logos get scaled up. This is on by default.
densityAware={false}β Turn it offdensityFactorβ How strong the effect is (0 = off, 0.5 = default, 1 = strong)
// Stronger density compensation
<LogoSoup logos={logos} densityFactor={0.8} />
// Turn it off
<LogoSoup logos={logos} densityAware={false} />How to handle logos with different shapes (wide vs tall). Default is 0.5.
Imagine you have two logos:
- Logo A: wide (200Γ100)
- Logo B: tall (100Γ200)
scaleFactor = 0 β Same width for all logos
- Logo A: 48Γ24 (short)
- Logo B: 48Γ96 (very tall)
scaleFactor = 1 β Same height for all logos
- Logo A: 96Γ48 (very wide)
- Logo B: 24Γ48 (narrow)
scaleFactor = 0.5 β Balanced (default)
- Neither gets too wide nor too tall
- Looks most natural
<LogoSoup logos={logos} scaleFactor={0.5} />How to align logos. Default is "visual-center-y".
"bounds"β Align by geometric center (bounding box)"visual-center"β Align by visual weight center (accounts for asymmetric logos)"visual-center-x"β Align by visual weight center horizontally only"visual-center-y"β Align by visual weight center vertically only
<LogoSoup logos={logos} alignBy="visual-center" />When enabled, logos are cropped to their content bounds and returned as base64 images. This removes any whitespace/padding baked into the original image files. Default is false.
<LogoSoup logos={logos} cropToContent />For custom layouts, use the useLogoSoup hook directly:
import { useLogoSoup } from "react-logo-soup";
function CustomGrid() {
const { isLoading, normalizedLogos } = useLogoSoup({
logos: [
{ src: "/logo1.svg", alt: "Logo 1" },
{ src: "/logo2.svg", alt: "Logo 2" },
],
});
if (isLoading) return <div>Loading...</div>;
return (
<div className="grid">
{normalizedLogos.map((logo) => (
<img
key={logo.src}
src={logo.src}
alt={logo.alt}
width={logo.normalizedWidth}
height={logo.normalizedHeight}
/>
))}
</div>
);
}When using the hook, you can apply visual center alignment with the getVisualCenterTransform helper:
import { useLogoSoup, getVisualCenterTransform } from "react-logo-soup";
function CustomGrid() {
const { normalizedLogos } = useLogoSoup({ logos });
return (
<div className="grid">
{normalizedLogos.map((logo) => (
<img
key={logo.src}
src={logo.src}
width={logo.normalizedWidth}
height={logo.normalizedHeight}
style={{ transform: getVisualCenterTransform(logo, "visual-center") }}
/>
))}
</div>
);
}Use renderImage to render logos with Next.js Image, add extra attributes, or fully control the <img> output. The callback receives all standard <img> attributes (src, alt, width, height, style):
import Image from "next/image";
<LogoSoup
logos={logos}
renderImage={(props) => (
<Image
src={props.src}
alt={props.alt}
width={props.width}
height={props.height}
/>
)}
/>;You can also use it to add attributes like loading or className:
<LogoSoup
logos={logos}
renderImage={(props) => <img {...props} loading="lazy" decoding="async" />}
/>;- Content Detection β Analyzes each logo to find its true boundaries, ignoring whitespace and padding
- Aspect Ratio Normalization β Scales logos based on their shape using the
scaleFactor - Density Compensation β Measures pixel density and adjusts size so dense logos don't overpower light ones
All processing happens client-side using canvas. No AI, fully deterministic.
The normalization core is plain JavaScript β React is just the wrapper. If you'd like to port Logo Soup to Vue, Svelte, Angular, or any other framework, go for it! We'd appreciate a link back to this repo, and let us know so we can link to your port from here.
- Logo Soup β Vanilla HTML/JS implementation, no framework required
bun install
bun test
bun run storybookMIT

