Web InnoventixFreeCode

Logos Strip Stat

Original · free

trusted-by logo strip (generic marks)

byWeb InnoventixReact + Tailwind
statxlogosstripstats
Open

Copy prompt gives Claude Code, Cursor or v0 a ready-to-paste prompt that recreates this exact component.

npx shadcn@latest add https://webinnoventix.com/r/statx-logos-strip.json
statx-logos-strip.tsx
"use client";

import { useId, useRef, useState } from "react";
import type { KeyboardEvent, ReactElement } from "react";
import { AnimatePresence, motion, useReducedMotion } from "motion/react";

const FILTERS = [
  { id: "all", label: "All" },
  { id: "fintech", label: "Fintech" },
  { id: "health", label: "Health" },
  { id: "logistics", label: "Logistics" },
  { id: "devtools", label: "Dev Tools" },
  { id: "commerce", label: "Commerce" },
] as const;

type FilterId = (typeof FILTERS)[number]["id"];
type Industry = Exclude<FilterId, "all">;

const INDUSTRY_LABEL: Record<Industry, string> = {
  fintech: "Fintech",
  health: "Health",
  logistics: "Logistics",
  devtools: "Dev Tools",
  commerce: "Commerce",
};

interface Mark {
  id: string;
  name: string;
  industry: Industry;
  metric: string;
  blurb: string;
  glyph: ReactElement;
}

const svgProps = {
  viewBox: "0 0 24 24",
  fill: "none",
  stroke: "currentColor",
  strokeWidth: 1.6,
  strokeLinecap: "round" as const,
  strokeLinejoin: "round" as const,
  "aria-hidden": true,
  className: "h-6 w-6",
};

const dot = { fill: "currentColor", stroke: "none" as const };

const MARKS: Mark[] = [
  {
    id: "northwind",
    name: "Northwind Labs",
    industry: "devtools",
    metric: "42% faster builds",
    blurb:
      "Northwind Labs moved their CI build cache to the platform and cut pipeline times by 42% across 90 repositories.",
    glyph: (
      <svg {...svgProps}>
        <path d="M4 18 12 4l8 14z" />
        <path d="M8.5 18 12 11l3.5 7" />
      </svg>
    ),
  },
  {
    id: "corevault",
    name: "Corevault",
    industry: "fintech",
    metric: "SOC 2 in 6 weeks",
    blurb:
      "Corevault cleared its SOC 2 Type II audit in six weeks using built-in evidence collection instead of a spreadsheet.",
    glyph: (
      <svg {...svgProps}>
        <path d="M12 3 20 6v6c0 5-3.5 7.6-8 9-4.5-1.4-8-4-8-9V6z" />
        <circle cx="12" cy="11" r="3" />
      </svg>
    ),
  },
  {
    id: "meridian",
    name: "Meridian Health",
    industry: "health",
    metric: "9.4M records synced",
    blurb:
      "Meridian Health keeps 9.4M patient records in sync across 60 clinics without a single reconciliation ticket.",
    glyph: (
      <svg {...svgProps}>
        <circle cx="12" cy="12" r="9" />
        <path d="M4 12h3.5l1.8-4 3 8 1.8-4H20" />
      </svg>
    ),
  },
  {
    id: "ironclad",
    name: "Ironclad Freight",
    industry: "logistics",
    metric: "18k shipments/day",
    blurb:
      "Ironclad Freight routes 18,000 shipments a day through one orchestration API, replacing four legacy schedulers.",
    glyph: (
      <svg {...svgProps}>
        <path d="M4 7.5 12 12l8-4.5" />
        <path d="M4 12.5 12 17l8-4.5" />
        <path d="M4 17 12 21.5 20 17" />
      </svg>
    ),
  },
  {
    id: "palette",
    name: "Palette Studio",
    industry: "commerce",
    metric: "31% faster checkout",
    blurb:
      "Palette Studio rebuilt its storefront over a weekend and shaved 31% off checkout latency for 1.1M shoppers.",
    glyph: (
      <svg {...svgProps}>
        <rect x="3" y="3" width="18" height="18" rx="5" />
        <circle cx="9" cy="9" r="1.5" {...dot} />
        <circle cx="15" cy="8.5" r="1.5" {...dot} />
        <circle cx="9.5" cy="15" r="1.5" {...dot} />
      </svg>
    ),
  },
  {
    id: "beaconpay",
    name: "Beacon Pay",
    industry: "fintech",
    metric: "0.02% dispute rate",
    blurb:
      "Beacon Pay holds a 0.02% dispute rate across 4M monthly transactions with real-time risk scoring at the edge.",
    glyph: (
      <svg {...svgProps}>
        <circle cx="12" cy="12" r="2.4" {...dot} />
        <path d="M8 16a6 6 0 0 1 0-8" />
        <path d="M5 19a10 10 0 0 1 0-14" />
        <path d="M16 8a6 6 0 0 1 0 8" />
        <path d="M19 5a10 10 0 0 1 0 14" />
      </svg>
    ),
  },
  {
    id: "verdant",
    name: "Verdant Bio",
    industry: "health",
    metric: "3x faster trials",
    blurb:
      "Verdant Bio onboards clinical trial sites three times faster with automated consent and eligibility flows.",
    glyph: (
      <svg {...svgProps}>
        <path d="M5 19C5 11 11 5 19 5c0 8-6 14-14 14z" />
        <path d="M9 15 16 8" />
      </svg>
    ),
  },
  {
    id: "cargolyn",
    name: "Cargolyn",
    industry: "logistics",
    metric: "99.98% on-time",
    blurb:
      "Cargolyn maintains 99.98% on-time delivery across 38 countries on a single live map with predictive ETAs.",
    glyph: (
      <svg {...svgProps}>
        <path d="M12 2.5 20 7v10l-8 4.5L4 17V7z" />
        <path d="M4 7l8 4.5L20 7" />
        <path d="M12 21.5V11.5" />
      </svg>
    ),
  },
  {
    id: "forgeline",
    name: "Forgeline",
    industry: "devtools",
    metric: "1.2M deploys/mo",
    blurb:
      "Forgeline runs 1.2M production deploys a month with zero-downtime rollbacks turned on by default.",
    glyph: (
      <svg {...svgProps}>
        <path d="M9 6 4 12l5 6" />
        <path d="M15 6l5 6-5 6" />
        <path d="M13 5 11 19" />
      </svg>
    ),
  },
  {
    id: "loomstack",
    name: "Loomstack",
    industry: "devtools",
    metric: "70% less alert noise",
    blurb:
      "Loomstack cut on-call alert noise by 70% after unifying logs, metrics, and traces into one query surface.",
    glyph: (
      <svg {...svgProps}>
        <rect x="4" y="10" width="3.4" height="10" rx="1.2" {...dot} />
        <rect x="10.3" y="5" width="3.4" height="15" rx="1.2" {...dot} />
        <rect x="16.6" y="13" width="3.4" height="7" rx="1.2" {...dot} />
      </svg>
    ),
  },
  {
    id: "solstice",
    name: "Solstice Retail",
    industry: "commerce",
    metric: "2.4M peak shoppers",
    blurb:
      "Solstice Retail scaled to 2.4M monthly shoppers through a Black Friday peak with zero incidents.",
    glyph: (
      <svg {...svgProps}>
        <circle cx="12" cy="12" r="4" />
        <path d="M12 2.5v2.2M12 19.3v2.2M2.5 12h2.2M19.3 12h2.2M5.2 5.2l1.6 1.6M17.2 17.2l1.6 1.6M18.8 5.2l-1.6 1.6M6.8 17.2l-1.6 1.6" />
      </svg>
    ),
  },
  {
    id: "atlasledger",
    name: "Atlas Ledger",
    industry: "fintech",
    metric: "Close in 2 days",
    blurb:
      "Atlas Ledger closes its books in two days instead of nine with continuous reconciliation across 14 entities.",
    glyph: (
      <svg {...svgProps}>
        <path d="M6 20 12 4l6 16" />
        <path d="M8.6 14h6.8" />
        <path d="M4 20h16" />
      </svg>
    ),
  },
];

const STATS: { value: string; label: string }[] = [
  { value: "400+", label: "Product teams" },
  { value: "4.6B", label: "Events / month" },
  { value: "99.98%", label: "Median uptime" },
  { value: "38", label: "Countries served" },
];

const cx = (...c: (string | false | null | undefined)[]) => c.filter(Boolean).join(" ");

const focusRing =
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:focus-visible:ring-offset-zinc-950";

interface MarkCardProps {
  mark: Mark;
  selected: boolean;
  interactive: boolean;
  onSelect?: () => void;
}

function MarkCard({ mark, selected, interactive, onSelect }: MarkCardProps) {
  const base =
    "group flex h-16 shrink-0 select-none items-center gap-3.5 rounded-2xl border px-5 transition-colors duration-200";
  const skin = selected
    ? "border-indigo-400/80 bg-indigo-50/70 ring-2 ring-indigo-500/30 dark:border-indigo-400/60 dark:bg-indigo-500/10"
    : "border-zinc-200/80 bg-white/60 hover:border-zinc-300 hover:bg-white dark:border-zinc-800 dark:bg-zinc-900/50 dark:hover:border-zinc-700";

  const glyphColor = selected
    ? "text-indigo-600 dark:text-indigo-400"
    : "text-zinc-400 group-hover:text-zinc-900 dark:text-zinc-500 dark:group-hover:text-white";
  const nameColor = selected
    ? "text-zinc-900 dark:text-white"
    : "text-zinc-600 group-hover:text-zinc-900 dark:text-zinc-300 dark:group-hover:text-white";

  const inner = (
    <>
      <span className={cx("flex h-9 w-9 items-center justify-center transition-colors duration-200", glyphColor)}>
        {mark.glyph}
      </span>
      <span className="flex flex-col items-start leading-tight">
        <span className={cx("text-[15px] font-semibold tracking-tight transition-colors duration-200", nameColor)}>
          {mark.name}
        </span>
        <span className="text-[10.5px] font-medium uppercase tracking-[0.14em] text-zinc-400 dark:text-zinc-500">
          {INDUSTRY_LABEL[mark.industry]}
        </span>
      </span>
    </>
  );

  if (!interactive) {
    return (
      <div aria-hidden="true" className={cx(base, skin)}>
        {inner}
      </div>
    );
  }

  return (
    <button
      type="button"
      aria-pressed={selected}
      aria-label={`${mark.name}, ${INDUSTRY_LABEL[mark.industry]}. ${selected ? "Hide" : "Show"} details.`}
      onClick={onSelect}
      className={cx(base, skin, focusRing, "cursor-pointer")}
    >
      {inner}
    </button>
  );
}

export default function StatxLogosStrip() {
  const shouldReduce = useReducedMotion();
  const reduce = shouldReduce === true;

  const [active, setActive] = useState<FilterId>("all");
  const [selected, setSelected] = useState<string | null>(null);
  const [playing, setPlaying] = useState(true);

  const filterRefs = useRef<(HTMLButtonElement | null)[]>([]);
  const groupLabelId = useId();
  const panelId = useId();

  const visible = active === "all" ? MARKS : MARKS.filter((m) => m.industry === active);
  const activeMark = MARKS.find((m) => m.id === selected) ?? null;
  const activeIndex = FILTERS.findIndex((f) => f.id === active);

  function pickFilter(index: number) {
    const f = FILTERS[index];
    setActive(f.id);
    setSelected(null);
    filterRefs.current[index]?.focus();
  }

  function onFilterKeyDown(e: KeyboardEvent<HTMLButtonElement>, index: number) {
    const last = FILTERS.length - 1;
    let next = index;
    if (e.key === "ArrowRight" || e.key === "ArrowDown") next = index === last ? 0 : index + 1;
    else if (e.key === "ArrowLeft" || e.key === "ArrowUp") next = index === 0 ? last : index - 1;
    else if (e.key === "Home") next = 0;
    else if (e.key === "End") next = last;
    else return;
    e.preventDefault();
    pickFilter(next);
  }

  return (
    <section className="relative w-full overflow-hidden bg-white text-zinc-900 dark:bg-zinc-950 dark:text-zinc-100">
      <style>{`
        @keyframes statx-scroll {
          from { transform: translateX(0); }
          to { transform: translateX(-50%); }
        }
        .statx-track { animation: statx-scroll 44s linear infinite; will-change: transform; }
        .statx-track[data-paused="true"] { animation-play-state: paused; }
        .statx-marquee:hover .statx-track,
        .statx-marquee:focus-within .statx-track { animation-play-state: paused; }
        @media (prefers-reduced-motion: reduce) {
          .statx-track { animation: none; }
        }
      `}</style>

      {/* atmosphere */}
      <div
        aria-hidden="true"
        className="pointer-events-none absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-zinc-300 to-transparent dark:via-zinc-700"
      />
      <div
        aria-hidden="true"
        className="pointer-events-none absolute left-1/2 top-0 h-72 w-[42rem] -translate-x-1/2 rounded-full bg-indigo-500/[0.07] blur-3xl dark:bg-indigo-500/[0.12]"
      />

      <div className="relative mx-auto max-w-6xl px-6 py-24 sm:py-28">
        {/* header */}
        <div className="mx-auto max-w-2xl text-center">
          <span className="inline-flex items-center gap-2 rounded-full border border-zinc-200 bg-zinc-50 px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.16em] text-zinc-500 dark:border-zinc-800 dark:bg-zinc-900 dark:text-zinc-400">
            <span className="relative flex h-1.5 w-1.5">
              <span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-emerald-400 opacity-70" />
              <span className="relative inline-flex h-1.5 w-1.5 rounded-full bg-emerald-500" />
            </span>
            Trusted by builders
          </span>
          <h2 className="mt-6 text-balance text-3xl font-semibold tracking-tight text-zinc-900 sm:text-4xl dark:text-white">
            The infrastructure behind 400+ product teams
          </h2>
          <p className="mt-4 text-pretty text-base leading-relaxed text-zinc-500 dark:text-zinc-400">
            Filter by industry, then select any team to see the number that moved. Real workloads, not logos on a wall.
          </p>
        </div>

        {/* controls */}
        <div className="mt-12 flex flex-col items-center gap-5">
          <div
            role="radiogroup"
            aria-labelledby={groupLabelId}
            className="flex flex-wrap items-center justify-center gap-1.5 rounded-full border border-zinc-200 bg-zinc-50/80 p-1.5 dark:border-zinc-800 dark:bg-zinc-900/60"
          >
            <span id={groupLabelId} className="sr-only">
              Filter teams by industry
            </span>
            {FILTERS.map((f, i) => {
              const isActive = f.id === active;
              return (
                <button
                  key={f.id}
                  ref={(el) => {
                    filterRefs.current[i] = el;
                  }}
                  type="button"
                  role="radio"
                  aria-checked={isActive}
                  tabIndex={i === activeIndex ? 0 : -1}
                  onClick={() => pickFilter(i)}
                  onKeyDown={(e) => onFilterKeyDown(e, i)}
                  className={cx(
                    "relative rounded-full px-4 py-1.5 text-sm font-medium transition-colors duration-200",
                    focusRing,
                    isActive
                      ? "text-white dark:text-zinc-900"
                      : "text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white",
                  )}
                >
                  {isActive && (
                    <motion.span
                      layoutId="statx-pill"
                      className="absolute inset-0 rounded-full bg-zinc-900 shadow-sm dark:bg-white"
                      transition={reduce ? { duration: 0 } : { type: "spring", stiffness: 420, damping: 34 }}
                    />
                  )}
                  <span className="relative z-10">{f.label}</span>
                </button>
              );
            })}
          </div>

          <div className="flex items-center gap-4">
            <p aria-live="polite" className="text-sm text-zinc-500 dark:text-zinc-400">
              <span className="font-semibold text-zinc-900 tabular-nums dark:text-white">{visible.length}</span>{" "}
              {visible.length === 1 ? "team" : "teams"}
              {active !== "all" && <> in {INDUSTRY_LABEL[active as Industry]}</>}
            </p>
            {!reduce && (
              <button
                type="button"
                onClick={() => setPlaying((p) => !p)}
                aria-label={playing ? "Pause the scrolling logos" : "Resume the scrolling logos"}
                aria-pressed={!playing}
                className={cx(
                  "inline-flex items-center gap-2 rounded-full border border-zinc-200 bg-white px-3 py-1.5 text-xs font-medium text-zinc-600 transition-colors hover:border-zinc-300 hover:text-zinc-900 dark:border-zinc-800 dark:bg-zinc-900 dark:text-zinc-400 dark:hover:border-zinc-700 dark:hover:text-white",
                  focusRing,
                )}
              >
                <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" className="h-3.5 w-3.5">
                  {playing ? <path d="M7 5h3v14H7zM14 5h3v14h-3z" /> : <path d="M8 5v14l11-7z" />}
                </svg>
                {playing ? "Pause" : "Play"}
              </button>
            )}
          </div>
        </div>

        {/* logo strip */}
        <div className="relative mt-12">
          {!reduce ? (
            <div className="statx-marquee relative overflow-hidden">
              <div
                aria-hidden="true"
                className="pointer-events-none absolute inset-y-0 left-0 z-10 w-16 bg-gradient-to-r from-white to-transparent sm:w-28 dark:from-zinc-950"
              />
              <div
                aria-hidden="true"
                className="pointer-events-none absolute inset-y-0 right-0 z-10 w-16 bg-gradient-to-l from-white to-transparent sm:w-28 dark:from-zinc-950"
              />
              <ul
                className="statx-track flex w-max items-center gap-4 py-2"
                data-paused={!playing}
                aria-label="Teams building on the platform"
              >
                {visible.map((m) => (
                  <li key={`a-${m.id}`}>
                    <MarkCard
                      mark={m}
                      selected={selected === m.id}
                      interactive
                      onSelect={() => setSelected((s) => (s === m.id ? null : m.id))}
                    />
                  </li>
                ))}
                {visible.map((m) => (
                  <li key={`b-${m.id}`} aria-hidden="true">
                    <MarkCard mark={m} selected={selected === m.id} interactive={false} />
                  </li>
                ))}
              </ul>
            </div>
          ) : (
            <ul className="flex flex-wrap items-center justify-center gap-3" aria-label="Teams building on the platform">
              {visible.map((m) => (
                <li key={m.id}>
                  <MarkCard
                    mark={m}
                    selected={selected === m.id}
                    interactive
                    onSelect={() => setSelected((s) => (s === m.id ? null : m.id))}
                  />
                </li>
              ))}
            </ul>
          )}
        </div>

        {/* detail panel */}
        <div className="mx-auto mt-8 min-h-[7rem] max-w-2xl">
          <AnimatePresence mode="wait">
            {activeMark ? (
              <motion.div
                key={activeMark.id}
                id={panelId}
                role="status"
                aria-live="polite"
                initial={reduce ? false : { opacity: 0, y: 10 }}
                animate={{ opacity: 1, y: 0 }}
                exit={reduce ? { opacity: 0 } : { opacity: 0, y: 8 }}
                transition={reduce ? { duration: 0 } : { duration: 0.26, ease: [0.22, 1, 0.36, 1] }}
                className="relative overflow-hidden rounded-3xl border border-zinc-200 bg-zinc-50/80 p-6 sm:p-7 dark:border-zinc-800 dark:bg-zinc-900/50"
              >
                <div className="flex items-start gap-5">
                  <span className="flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl bg-white text-indigo-600 shadow-sm ring-1 ring-zinc-200 dark:bg-zinc-800 dark:text-indigo-400 dark:ring-zinc-700">
                    {activeMark.glyph}
                  </span>
                  <div className="min-w-0 flex-1">
                    <div className="flex flex-wrap items-center gap-x-3 gap-y-1">
                      <span className="text-base font-semibold tracking-tight text-zinc-900 dark:text-white">
                        {activeMark.name}
                      </span>
                      <span className="rounded-full bg-indigo-100 px-2.5 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-indigo-700 dark:bg-indigo-500/15 dark:text-indigo-300">
                        {INDUSTRY_LABEL[activeMark.industry]}
                      </span>
                    </div>
                    <p className="mt-3 text-2xl font-semibold tracking-tight text-zinc-900 dark:text-white">
                      {activeMark.metric}
                    </p>
                    <p className="mt-2 text-sm leading-relaxed text-zinc-600 dark:text-zinc-400">{activeMark.blurb}</p>
                  </div>
                  <button
                    type="button"
                    onClick={() => setSelected(null)}
                    aria-label={`Dismiss details for ${activeMark.name}`}
                    className={cx(
                      "shrink-0 rounded-full p-1.5 text-zinc-400 transition-colors hover:bg-zinc-200/70 hover:text-zinc-900 dark:hover:bg-zinc-800 dark:hover:text-white",
                      focusRing,
                    )}
                  >
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.8} aria-hidden="true" className="h-4 w-4">
                      <path d="M6 6l12 12M18 6 6 18" strokeLinecap="round" />
                    </svg>
                  </button>
                </div>
              </motion.div>
            ) : (
              <p className="flex h-28 items-center justify-center rounded-3xl border border-dashed border-zinc-200 text-center text-sm text-zinc-400 dark:border-zinc-800 dark:text-zinc-500">
                Select a team to see the number that moved.
              </p>
            )}
          </AnimatePresence>
        </div>

        {/* stats */}
        <dl className="mt-16 grid grid-cols-2 gap-x-6 gap-y-8 border-t border-zinc-200 pt-10 sm:grid-cols-4 dark:border-zinc-800">
          {STATS.map((s) => (
            <div key={s.label} className="text-center">
              <dt className="sr-only">{s.label}</dt>
              <dd className="text-3xl font-semibold tracking-tight text-zinc-900 tabular-nums sm:text-4xl dark:text-white">
                {s.value}
              </dd>
              <p className="mt-1.5 text-xs font-medium uppercase tracking-[0.12em] text-zinc-400 dark:text-zinc-500">
                {s.label}
              </p>
            </div>
          ))}
        </dl>
      </div>
    </section>
  );
}

Dependencies

motion

Licence

Built by Web Innoventix. Free for personal and commercial use, no attribution required.

Built by Web Innoventix

Need a custom interface, a full website, or SEO that gets you cited by AI? We design, build and rank it end to end.

Get a free quote

Similar components

Browse all →
Four Stat Metric Band

Four Stat Metric Band

Original

A four-column metric band with gradient figures inside a hairline-divided card, ideal for headline numbers like uptime, latency and growth.

Labelled Stats With Dividers

Labelled Stats With Dividers

Original

Three centred stats separated by responsive dividers, each pairing a headline figure with an uppercase label and supporting detail.

Trusted By Logo Cloud

Trusted By Logo Cloud

Original

A responsive six-up logo strip using simple inline-SVG marks and wordmarks with a grayscale-to-colour hover, for a trusted-by section.

Hero Stat With Supporting Copy

Hero Stat With Supporting Copy

Original

A two-column layout pairing one oversized hero statistic with a supporting paragraph and a checklist card explaining the number.

Count-up stats reveal

Count-up stats reveal

Original

A four-card stat band whose gradient numbers count up from zero as the section scrolls into view, with staggered blur-in cards, a pulsing eyebrow, floating aurora blobs and a shimmering underline sweep.

Animated SVG progress rings

Animated SVG progress rings

Original

Four circular SVG progress rings that draw their gradient arcs and count up to their target percentage the moment they enter view, over a slowly rotating conic halo with a soft glow pulse behind each ring.

Staggered stat band with marquee ticker

Staggered stat band with marquee ticker

Original

A dark stat band where 3D-tilt cards stagger into view with count-up figures over an animated gradient mesh, finished by an infinite marquee ticker of highlight chips that pauses on hover.

Counter Row Stat

Counter Row Stat

Original

animated counter stats row

Cards Stat

Cards Stat

Original

stat cards with icons

Gradient Stat

Gradient Stat

Original

gradient stats band

Split Stat

Split Stat

Original

stats beside copy

Icons Stat

Icons Stat

Original

icon stat grid