# Team Grid

> A responsive grid of headshots with names, titles, and social links. Use it on an about page to introduce the real people behind your product.

A shadcn/ui block from the [@shadcn-ui-blocks](https://www.shadcn-ui-blocks.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/shadcn-ui-blocks/marketing-about-sections-team-grid).

- Page, with a live preview: https://shadcn.exchange/r/shadcn-ui-blocks/marketing-about-sections-team-grid
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/shadcn-ui-blocks/marketing-about-sections-team-grid-light-7d5032d80556ead4.png
- Registry item: https://www.shadcn-ui-blocks.com/r/marketing-about-sections-team-grid.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://www.shadcn-ui-blocks.com/r/marketing-about-sections-team-grid.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `@icons-pack/react-simple-icons`

## Files

### `components/blocks/marketing/about-sections/team-grid.tsx`

```tsx
import { Card, CardContent } from '@/components/ui/card';
import { SiGithub } from '@icons-pack/react-simple-icons';

import { Linkedin, Twitter } from '@/components/ui/brand-icons';

const teamMembers = [
  {
    name: 'Sarah Johnson',
    role: 'CEO & Founder',
    image:
      'https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?q=80&w=800',
    bio: 'With over 15 years of industry experience, Sarah leads our company vision and strategy.',
    social: {
      twitter: '#',
      linkedin: '#',
      github: '#',
    },
  },
  {
    name: 'Michael Chen',
    role: 'CTO',
    image:
      'https://images.unsplash.com/photo-1560250097-0b93528c311a?q=80&w=800',
    bio: 'Michael oversees our technical direction and ensures we stay at the cutting edge.',
    social: {
      twitter: '#',
      linkedin: '#',
      github: '#',
    },
  },
  {
    name: 'Jessica Rivera',
    role: 'Design Director',
    image:
      'https://images.unsplash.com/photo-1580489944761-15a19d654956?q=80&w=800',
    bio: 'Jessica brings a decade of UX/UI expertise and leads our award-winning design team.',
    social: {
      twitter: '#',
      linkedin: '#',
    },
  },
  {
    name: 'David Kim',
    role: 'Lead Developer',
    image:
      'https://images.unsplash.com/photo-1599566150163-29194dcaad36?q=80&w=800',
    bio: 'David is the technical mastermind behind our most complex and successful projects.',
    social: {
      linkedin: '#',
      github: '#',
    },
  },
  {
    name: 'Aisha Patel',
    role: 'Marketing Director',
    image:
      'https://images.unsplash.com/photo-1531123897727-8f129e1688ce?q=80&w=800',
    bio: 'Aisha develops our marketing strategies and helps clients amplify their message.',
    social: {
      twitter: '#',
      linkedin: '#',
    },
  },
  {
    name: 'Robert Wilson',
    role: 'Project Manager',
    image:
      'https://images.unsplash.com/photo-1519085360753-af0119f7cbe7?q=80&w=800',
    bio: 'Robert ensures our projects run smoothly and are delivered on time and on budget.',
    social: {
      linkedin: '#',
    },
  },
];

export default function AboutSectionTeamGrid() {
  return (
    <section className="container mx-auto space-y-12 px-4 py-24 md:px-6 2xl:max-w-[1400px]">
      <div className="mx-auto max-w-3xl space-y-4 text-center">
        <h2 className="text-3xl font-bold">Meet Our Team</h2>
        <p className="text-muted-foreground">
          Our diverse team of talented professionals is passionate about
          creating exceptional digital experiences that help our clients
          succeed.
        </p>
      </div>

      <div className="grid grid-cols-1 gap-8 md:grid-cols-2 lg:grid-cols-3">
        {teamMembers.map((member) => (
          <Card key={member.name} className="overflow-hidden p-0">
            <div className="relative aspect-[4/3]">
              <img
                src={member.image}
                alt={member.name}
                className="object-cover object-center"
                sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
              />
            </div>
            <CardContent className="space-y-4 p-6 pt-0">
              <div>
                <h3 className="text-lg font-bold">{member.name}</h3>
                <p className="text-primary text-sm font-medium">
                  {member.role}
                </p>
              </div>
              <p className="text-muted-foreground text-sm">{member.bio}</p>
              <div className="flex gap-4">
                {member.social.twitter && (
                  <a
                    href={member.social.twitter}
                    className="text-muted-foreground hover:text-primary"
                  >
                    <Twitter className="h-4 w-4" />
                    <span className="sr-only">Twitter</span>
                  </a>
                )}
                {member.social.linkedin && (
                  <a
                    href={member.social.linkedin}
                    className="text-muted-foreground hover:text-primary"
                  >
                    <Linkedin className="h-4 w-4" />
                    <span className="sr-only">LinkedIn</span>
                  </a>
                )}
                {member.social.github && (
                  <a
                    href={member.social.github}
                    className="text-muted-foreground hover:text-primary"
                  >
                    <SiGithub className="h-4 w-4" />
                    <span className="sr-only">GitHub</span>
                  </a>
                )}
              </div>
            </CardContent>
          </Card>
        ))}
      </div>
    </section>
  );
}
```

### `components/ui/card.tsx`

```tsx
import * as React from "react"

import { cn } from "@/lib/utils"

function Card({
  className,
  size = "default",
  ...props
}: React.ComponentProps<"div"> & { size?: "default" | "sm" }) {
  return (
    <div
      data-slot="card"
      data-size={size}
      className={cn(
        "group/card flex flex-col gap-6 overflow-hidden rounded-xl bg-card py-6 text-sm text-card-foreground shadow-xs ring-1 ring-foreground/10 has-[>img:first-child]:pt-0 data-[size=sm]:gap-4 data-[size=sm]:py-4 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
        className
      )}
      {...props}
    />
  )
}

function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="card-header"
      className={cn(
        "group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-6 group-data-[size=sm]/card:px-4 has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-6 group-data-[size=sm]/card:[.border-b]:pb-4",
        className
      )}
      {...props}
    />
  )
}

function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="card-title"
      className={cn(
        "font-heading text-base leading-normal font-medium group-data-[size=sm]/card:text-sm",
        className
      )}
      {...props}
    />
  )
}

function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="card-description"
      className={cn("text-sm text-muted-foreground", className)}
      {...props}
    />
  )
}

function CardAction({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="card-action"
      className={cn(
        "col-start-2 row-span-2 row-start-1 self-start justify-self-end",
        className
      )}
      {...props}
    />
  )
}

function CardContent({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="card-content"
      className={cn("px-6 group-data-[size=sm]/card:px-4", className)}
      {...props}
    />
  )
}

function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="card-footer"
      className={cn(
        "flex items-center rounded-b-xl px-6 group-data-[size=sm]/card:px-4 [.border-t]:pt-6 group-data-[size=sm]/card:[.border-t]:pt-4",
        className
      )}
      {...props}
    />
  )
}

export {
  Card,
  CardHeader,
  CardFooter,
  CardTitle,
  CardAction,
  CardDescription,
  CardContent,
}
```

### `components/ui/brand-icons.tsx`

```tsx
import type { ReactNode, SVGProps } from "react"

type BrandIconProps = Omit<SVGProps<SVGSVGElement>, "color"> & {
  title?: string
  color?: string
  size?: number | string
}

/**
 * The brand glyphs Simple Icons has dropped at their owners' request. Every
 * other brand comes straight from the package, imported where it is used
 * (`import { SiGithub } from "@icons-pack/react-simple-icons"`); these three
 * keep the last path Simple Icons published, on its 24 unit grid, and take the
 * package's props (title, color, size) so both read alike in a block.
 */
function BrandSvg({
  children,
  color = "currentColor",
  size = 24,
  title,
  ...props
}: BrandIconProps & { children: ReactNode }) {
  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      width={size}
      height={size}
      fill={color}
      viewBox="0 0 24 24"
      {...props}
    >
      <title>{title}</title>
      {children}
    </svg>
  )
}

function Linkedin(props: BrandIconProps) {
  return (
    <BrandSvg title="LinkedIn" {...props}>
      <path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" />
    </BrandSvg>
  )
}

function Slack(props: BrandIconProps) {
  return (
    <BrandSvg title="Slack" {...props}>
      <path d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zM6.313 15.165a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zM8.834 6.313a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zM18.956 8.834a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zM17.688 8.834a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zM15.165 18.956a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zM15.165 17.688a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z" />
    </BrandSvg>
  )
}

function Twitter(props: BrandIconProps) {
  return (
    <BrandSvg title="Twitter" {...props}>
      <path d="M23.4 4.8c-.8.4-1.7.6-2.6.7.9-.6 1.6-1.5 2-2.5-.9.5-1.9.9-2.9 1.1a4.5 4.5 0 0 0-7.8 4.1A12.8 12.8 0 0 1 2.8 3.5a4.5 4.5 0 0 0 1.4 6.1c-.7 0-1.4-.2-2-.6v.1c0 2.2 1.6 4.1 3.6 4.5-.4.1-.8.2-1.2.2-.3 0-.6 0-.9-.1.6 1.8 2.2 3.1 4.2 3.1a9.1 9.1 0 0 1-5.6 1.9c-.4 0-.7 0-1.1-.1a12.8 12.8 0 0 0 7 2c8.3 0 12.9-6.9 12.9-12.9v-.6c.9-.6 1.7-1.4 2.3-2.3Z" />
    </BrandSvg>
  )
}

export { Linkedin, Slack, Twitter }
```
