Skip to main content
These options are shared across every framework adapter. They’re passed as component props (React), composable args (Vue), or process() options (Svelte/Solid/Angular/Vanilla).

Core Options

logos

logos
(string | { src: string; alt?: string })[]
required
Array of logo URLs or objects with src and optional alt text. Use objects to provide accessible alt text for each logo.
// Plain strings
const logos = ["/logos/acme.svg", "/logos/globex.svg"];

// Objects with alt text (recommended)
const logos = [
  { src: "/logos/acme.svg", alt: "Acme Corp" },
  { src: "/logos/globex.svg", alt: "Globex" },
];

// Mixed
const logos = [
  "/logos/acme.svg",
  { src: "/logos/globex.svg", alt: "Globex" },
];

baseSize

baseSize
number
default:"48"
Target size for logos in pixels. This is the baseline that all normalization is relative to. Larger values produce larger logos.
<LogoSoup logos={logos} baseSize={64} />

scaleFactor

scaleFactor
number
default:"0.5"
Controls how logos with different aspect ratios are balanced. This uses Dan Paquette’s technique where the normalized width is calculated as aspectRatio ^ scaleFactor * baseSize.
ValueBehaviorWhen to use
0All logos get the same widthWhen you want a uniform grid
0.5Balanced (default)Most use cases
1All logos get the same heightWhen vertical alignment matters most
Imagine two logos: Logo A is wide (200×100) and Logo B is tall (100×200).scaleFactor = 0 — Same width for all:
  • Logo A: 48×24 (short)
  • Logo B: 48×96 (very tall)
scaleFactor = 1 — Same height for all:
  • Logo A: 96×48 (very wide)
  • Logo B: 24×48 (narrow)
scaleFactor = 0.5 — Balanced:
  • Neither gets too wide nor too tall
  • Looks most natural

densityAware

densityAware
boolean
default:"true"
When enabled, Logo Soup measures the “visual weight” (pixel density) of each logo and adjusts sizing accordingly. Dense, solid logos get scaled down. Light, thin logos get scaled up.Set to false to disable density compensation entirely.
// Disable density compensation
<LogoSoup logos={logos} densityAware={false} />

densityFactor

densityFactor
number
default:"0.5"
Controls how strongly density affects the result. Only applies when densityAware is true.
ValueEffect
0No density compensation (same as densityAware: false)
0.5Moderate compensation (default)
1Strong compensation
// Stronger density compensation
<LogoSoup logos={logos} densityFactor={0.8} />

cropToContent

cropToContent
boolean
default:"false"
When enabled, logos are cropped to their detected content bounds and re-rendered as blob URLs. This removes any whitespace or padding baked into the original image files.The cropped images are available as logo.croppedSrc on each NormalizedLogo object.
<LogoSoup logos={logos} cropToContent />
Cropping creates blob URLs that are cleaned up when the engine is destroyed. Don’t store croppedSrc values beyond the engine’s lifetime.

contrastThreshold

contrastThreshold
number
default:"10"
Minimum contrast distance (in RGB space) for a pixel to be considered “content” during content detection. Higher values ignore more low-contrast details near the background color.You rarely need to change this. Increase it if logos with very subtle gradients or shadows are getting incorrect bounds.

backgroundColor

backgroundColor
string | [number, number, number]
The background color the logos will be displayed on. Used for two things:
  1. Contrast detection on opaque logos (logos without transparency) — the engine needs to know the background to distinguish content from the background
  2. Irradiation compensation — light logos on dark backgrounds appear optically larger; this option enables the correction
Accepts CSS color strings ("#1a1a1a", "rgb(26, 26, 26)", "hsl(0, 0%, 10%)") or RGB tuples ([26, 26, 26]).When omitted, the engine auto-detects the background by analyzing the perimeter pixels of each image. This works well for logos with transparent backgrounds. For logos on opaque backgrounds (like JPEGs), providing the actual background color produces better results.
// Dark mode
<LogoSoup logos={logos} backgroundColor="#1a1a1a" />

// RGB tuple
<LogoSoup logos={logos} backgroundColor={[26, 26, 26]} />

React Component Options

These options are only available on the React <LogoSoup> component.

gap

gap
number | string
default:"28"
Space between logos. Accepts a pixel number or a CSS string value.
<LogoSoup logos={logos} gap={24} />
<LogoSoup logos={logos} gap="1.5rem" />

alignBy

alignBy
AlignmentMode
default:"visual-center-y"
How to align logos within the row. See Alignment Modes below.
<LogoSoup logos={logos} alignBy="visual-center" />

renderImage

renderImage
(props: ImageRenderProps) => ReactNode
Custom image renderer. Receives all standard <img> attributes (src, alt, width, height, style). Use this to integrate with Next.js Image, add lazy loading, or fully control the <img> output.
import Image from "next/image";

<LogoSoup
  logos={logos}
  renderImage={(props) => (
    <Image src={props.src} alt={props.alt} width={props.width} height={props.height} />
  )}
/>

className

className
string
CSS class name applied to the container <div>.

style

style
CSSProperties
Inline styles applied to the container <div>. Merged with the default container styles (text-align: center, text-wrap: balance).

onNormalized

onNormalized
(logos: NormalizedLogo[]) => void
Callback fired when normalization completes. Receives the array of normalized logos. Useful for analytics, debugging, or syncing state with external systems.
<LogoSoup
  logos={logos}
  onNormalized={(normalized) => {
    console.log("Normalized:", normalized.length, "logos");
  }}
/>

Alignment Modes

Used with the alignBy prop (React component) or getVisualCenterTransform helper (all frameworks).
ModeDescription
"bounds"Align by geometric center of the bounding box. No transform applied.
"visual-center"Align by visual weight center on both axes. Compensates for asymmetric logos where the “heavy” part isn’t centered.
"visual-center-x"Visual center horizontally only. Vertical alignment uses bounds.
"visual-center-y"Visual center vertically only (default). Horizontal alignment uses bounds. Best for horizontal logo rows where vertical balance matters most.

Using with the hook/composable

When building custom layouts (not using the React <LogoSoup> component), apply alignment with getVisualCenterTransform:
import { getVisualCenterTransform } from "@sanity-labs/logo-soup";

const transform = getVisualCenterTransform(logo, "visual-center-y");
// Returns "translate(0px, -2.3px)" or undefined

NormalizedLogo Object

Each processed logo is a NormalizedLogo with these properties:
PropertyTypeDescription
srcstringOriginal image URL
altstringAlt text (empty string if not provided)
originalWidthnumberNatural width of the source image
originalHeightnumberNatural height of the source image
normalizedWidthnumberComputed display width after normalization
normalizedHeightnumberComputed display height after normalization
aspectRationumberContent aspect ratio (width / height)
contentBoxBoundingBox?Detected content bounds within the image
pixelDensitynumber?Measured visual density (0–1)
visualCenterVisualCenter?Visual weight center with offset from geometric center
croppedSrcstring?Blob URL of the cropped image (when cropToContent is enabled)