WebberUI

Team + Logo Wall

A team member grid that staggers in, paired with an infinitely scrolling customer logo marquee — a good fit for the trust block on an about page or a home page.

This is a WebberUI Pro component

Free during the launch campaign: sign up or sign in, then hit “Copy install command” in the preview above and it installs straight away — no payment, no credit card. The command below returns 401 while you are signed out.

How to install Pro components →See the plans →

Loading preview…
npx shadcn@latest add "https://webberui.com/r/team-logo-wall.json?t=<install token>"

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

4
40
<TeamLogoWall />

Installation

npx shadcn@latest add "https://webberui.com/r/team-logo-wall.json?t=<install token>"

Or, once registries are configured in components.json, install it as @webberui/team-logo-wall.

Usage

import {
  TeamLogoWall,
  type TeamMemberData,
  type LogoData,
} from "@/components/ui/team-logo-wall";

const members: TeamMemberData[] = [
  { name: "Ada Lovelace", role: "Founder / CEO", avatar: "/team/ada.jpg" },
  { name: "Alan Turing", role: "Chief Technology Officer" },
];

const logos: LogoData[] = [
  { name: "Vercel", src: "/logos/vercel.svg", href: "https://vercel.com" },
  { name: "Linear", src: "/logos/linear.svg" },
];

<TeamLogoWall
  members={members}
  logos={logos}
  eyebrow="Our team"
  title="Building animation-first interfaces"
  logosLabel="Brands that trust us"
/>;

TeamGrid and LogoMarquee can also be imported on their own if you only want one half:

import { TeamGrid, LogoMarquee } from "@/components/ui/team-logo-wall";

<TeamGrid members={members} columns={3} />
<LogoMarquee logos={logos} speed={30} direction="right" />

Props

TeamLogoWall

PropTypeDefaultDescription
membersTeamMemberData[]The array of team member data
logosLogoData[]The array of customer/partner brand logo data
eyebrowReact.ReactNodeThe kicker above the title
titleReact.ReactNodeThe section's main heading
descriptionReact.ReactNodeDescriptive text below the main heading
logosLabelReact.ReactNodeCaption above the logo marquee
columnsnumber4Column count for the team grid (2–6, degrading automatically at low breakpoints)
marqueeSpeednumber40The logo marquee's offset per second (px)
marqueeDirection"left" | "right""left"Direction the marquee travels
pauseOnHoverbooleantruePause the marquee on mouse hover or keyboard focus
labelstring"團隊與合作品牌" (Team and partner brands)Accessible label for the whole region

TeamGrid

PropTypeDefaultDescription
membersTeamMemberData[]The array of team member data
columnsnumber4Column count (2–6, degrading automatically at low breakpoints)
staggernumber0.08Reveal interval between cards (seconds)
delaynumber0Delay before the reveal starts (seconds)
oncebooleantruePlay only the first time the element enters the viewport
labelstring"團隊成員" (Team members)Accessible label for the whole region

LogoMarquee

PropTypeDefaultDescription
logosLogoData[]The array of customer logo data
speednumber40Offset per second (px)
direction"left" | "right""left"Direction of travel
gapnumber48Spacing between logos (px)
pauseOnHoverbooleantruePause on mouse hover or keyboard focus
labelstring"合作品牌" (Partner brands)Accessible label for the whole region

TeamMemberData

FieldTypeDescription
namestringMember name
rolestringJob title or role (optional)
avatarstringAvatar image URL; when not provided, the first character of the name is shown
hrefstringLink the card goes to when clicked (optional)

LogoData

FieldTypeDescription
namestringBrand name, also used as the alt / accessible text
srcstringLogo image URL
nodeReact.ReactNodeA custom logo node (an inline SVG, for example), which takes precedence over src
hrefstringLink to go to when clicked (optional)

How it works

  • Two stacked parts: the top half is the team grid, whose cards fade in and float up one after another by stagger when they enter the viewport; the bottom half is the logo marquee, scrolling smoothly and infinitely with requestAnimationFrame.
  • Seamless loop: the marquee renders two identical copies of the content, measures the width of one copy, and cycles the offset within (-distance, 0], so the switch point is imperceptible; a ResizeObserver re-measures whenever the container size changes.
  • Fading at both ends: the marquee uses mask-image so logos dissolve naturally at the left and right boundaries.
  • Greyscale logos: by default they are presented in greyscale at reduced opacity, returning to full color and full opacity when the cursor hovers that logo.
  • Standalone use: TeamGrid, LogoMarquee, and TeamMemberCard can all be imported on their own.
  • Tuning points: the animation durations are based on var(--wb-duration-fast,200ms) and var(--wb-ease-out,cubic-bezier(0.22,1,0.36,1)), so you can override them uniformly through CSS variables.

Accessibility

  • When the user has "reduce motion" enabled at the system level, the team grid is presented statically (with no stagger) and the logo wall switches to a centered wrapping layout that no longer scrolls.
  • The team grid is a role="list" and the member cards are role="listitem", with an aria-label on the region.
  • The marquee's second copy is marked aria-hidden, which keeps assistive technology from announcing it twice.
  • Members and logos with an href are focusable links with a clear focus-visible outline; focusing a link inside the marquee pauses the scrolling (with pauseOnHover), which makes keyboard operation easier.
  • Avatar alt is left empty (decorative) and the name is presented separately as text; a logo image's alt comes from the brand's name.

On this page